This is the code for the statistical analysis for “Vowel Acoustics as Predictors of Speech Intelligibility in Dysarthria.”

Loading Packages

devtools::install_github("AustinRThompson/mslTools")
Downloading GitHub repo AustinRThompson/mslTools@HEAD
These packages have more recent versions available.
It is recommended to update all of them.
Which would you like to update?

1: All                            
2: CRAN packages only             
3: None                           
4: openssl (2.0.0 -> 2.0.1) [CRAN]
1
openssl (2.0.0 -> 2.0.1) [CRAN]
Installing 1 packages: openssl

  There is a binary version available but the source version is later:
yes
installing the source package ‘openssl’

trying URL 'https://cran.rstudio.com/src/contrib/openssl_2.0.1.tar.gz'
Content type 'application/x-gzip' length 1204569 bytes (1.1 MB)
==================================================
downloaded 1.1 MB

* installing *source* package ‘openssl’ ...
** package ‘openssl’ successfully unpacked and MD5 sums checked
** using staged installation
Homebrew 2.4.5
Homebrew/homebrew-core (git revision d2eb63; last commit 2020-07-11)
Using PKG_CFLAGS=-I/usr/local/opt/openssl/include -I/usr/local/opt/openssl@1.1/include
--------------------------- [ANTICONF] --------------------------------
Configuration failed because openssl was not found. Try installing:
 * deb: libssl-dev (Debian, Ubuntu, etc)
 * rpm: openssl-devel (Fedora, CentOS, RHEL)
 * csw: libssl_dev (Solaris)
 * brew: openssl (Mac OSX)
If openssl is already installed, check that 'pkg-config' is in your
PATH and PKG_CONFIG_PATH contains a openssl.pc file. If pkg-config
is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:
R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'
-------------------------- [ERROR MESSAGE] ---------------------------
tools/version.c:1:10: fatal error: 'openssl/opensslv.h' file not found
#include <openssl/opensslv.h>
         ^~~~~~~~~~~~~~~~~~~~
1 error generated.
--------------------------------------------------------------------
ERROR: configuration failed for package ‘openssl’
* removing ‘/Library/Frameworks/R.framework/Versions/4.0/Resources/library/openssl’
* restoring previous ‘/Library/Frameworks/R.framework/Versions/4.0/Resources/library/openssl’
installation of package ‘openssl’ had non-zero exit status
The downloaded source packages are in
    ‘/private/var/folders/2s/c8b_6s1s5tgcqqt271kpjw4r0000gn/T/RtmpPx425O/downloaded_packages’
  
   checking for file ‘/private/var/folders/2s/c8b_6s1s5tgcqqt271kpjw4r0000gn/T/RtmpPx425O/remotes58b052e11089/AustinRThompson-mslTools-58d506d/DESCRIPTION’ ...
  
✔  checking for file ‘/private/var/folders/2s/c8b_6s1s5tgcqqt271kpjw4r0000gn/T/RtmpPx425O/remotes58b052e11089/AustinRThompson-mslTools-58d506d/DESCRIPTION’ (2.3s)

  
─  preparing ‘mslTools’:

  
   checking DESCRIPTION meta-information ...
  
✔  checking DESCRIPTION meta-information

  
   
  
─  checking for LF line-endings in source and make files and shell scripts (585ms)

  
─  checking for empty or unneeded directories

  
─  building ‘mslTools_0.0.0.9000.tar.gz’

  
   
* installing *source* package ‘mslTools’ ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
Warning messages:
1: package ‘tidyr’ was built under R version 4.0.5 
2: package ‘readr’ was built under R version 4.0.5 
** help
No man pages found in package  ‘mslTools’ 
*** installing help indices
*** copying figures
** building package indices
** testing if installed package can be loaded from temporary location
Warning: package ‘tidyr’ was built under R version 4.0.5
Warning: package ‘readr’ was built under R version 4.0.5
** testing if installed package can be loaded from final location
Warning: package ‘tidyr’ was built under R version 4.0.5
Warning: package ‘readr’ was built under R version 4.0.5
** testing if installed package keeps a record of temporary installation path
* DONE (mslTools)

Upload Datasets


Reliability <- rio::import("Prepped Data/Reliability Data.csv")
AcousticData <- rio::import("Prepped Data/AcousticMeasures.csv") %>%
  dplyr::mutate(intDiff = VAS - transAcc)

AcousticData <- AcousticData %>%
  dplyr::filter(!grepl("_rel", Speaker)) %>%
  dplyr::select(c(Speaker, Sex, Etiology, vowel_ED_b, VSA_b, autoVSA,
                  Hull_b,Hull_bVSD_25, Hull_bVSD_50, Hull_bVSD_75,
                  VAS, transAcc)) %>%
  dplyr::mutate(Etiology = as.factor(Etiology),
                Sex = as.factor(Sex),
                Speaker = as.factor(Speaker))

Listeners <- rio::import("Prepped Data/Listener_Demographics.csv") %>%
  dplyr::select(!c(StartDate:proloficID, Q2.4_6_TEXT, Q3.2_8_TEXT, AudioCheck:EP3))

Listeners$race[Listeners$Q3.3_7_TEXT == "Native American/ African amercing"] <- "Biracial or Multiracial"

Inter-rater Reliability

Two raters (the first two authors) completed vowel segmentation for the speakers. To calculate inter-rater reliability, 20% of the speakers were segmented again by the other rater. Two-way intraclass coefficients were computed for the extracted F1 and F2 from the temporal midpoint of the vowel segments. Since only one set of ratings will be used in the data analysis, we focus on the single ICC results and interpretation. However, we also report the average ICC values to be comprehensive.


## Creating new data frames to calculate ICC for extracted F1 and F2 values

F1_Rel <- Reliability %>%
  dplyr::select(c(F1, F1_rel))

F2_Rel <- Reliability %>%
  dplyr::select(c(F2, F2_rel))
  
## Single ICC for F1
Single_F1 <- irr::icc(F1_Rel, model = "twoway", type = "agreement", unit = "single")

## Average ICC for F1
Average_F1 <- irr::icc(F1_Rel, model = "twoway", type = "agreement", unit = "average")

## Single ICC for F2
Single_F2 <- irr::icc(F2_Rel, model = "twoway", type = "agreement", unit = "single")

## Average ICC for F2
Average_F2 <- irr::icc(F2_Rel, model = "twoway", type = "agreement", unit = "average")

## Inter-rater reliability results and interpretation

print(paste("Single ICC for F1 is ", round(Single_F1$value, digits = 3), ". ", 
            "The 95% CI is [", round(Single_F1$lbound, digits = 3), " - ", round(Single_F1$ubound, digits = 3), "].", sep = ""))
[1] "Single ICC for F1 is 0.866. The 95% CI is [0.837 - 0.89]."
print(paste("Single ICC for F2 is ", round(Single_F2$value, digits = 3), ". ", 
            "The 95% CI is [", round(Single_F2$lbound, digits = 3), " - ", round(Single_F2$ubound, digits = 3), "].", sep = ""))
[1] "Single ICC for F2 is 0.931. The 95% CI is [0.916 - 0.944]."
print(paste("Average ICC for F1 is ", round(Average_F1$value, digits = 3), ". ", 
            "The 95% CI is [", round(Average_F1$lbound, digits = 3), " - ", round(Average_F1$ubound, digits = 3), "].", sep = ""))
[1] "Average ICC for F1 is 0.928. The 95% CI is [0.911 - 0.942]."
print(paste("Average ICC for F2 is ", round(Average_F2$value, digits = 3), ". ", 
            "The 95% CI is [", round(Average_F2$lbound, digits = 3), " - ", round(Average_F2$ubound, digits = 3), "].", sep = ""))
[1] "Average ICC for F2 is 0.964. The 95% CI is [0.956 - 0.971]."
print("Thus, interrater reliability for the extracted F1 and F2 values from the vowel segments was good to excellent.")
[1] "Thus, interrater reliability for the extracted F1 and F2 values from the vowel segments was good to excellent."
## Removing extra data frames from environment

rm(F1_Rel, F2_Rel, Reliability, Single_F1, Single_F2, Average_F1, Average_F2)

Descriptive Statistics

Correlations

CorrMatrix <- AcousticData %>%
  dplyr::select(VSA_b, vowel_ED_b, Hull_b, Hull_bVSD_25, Hull_bVSD_75, VAS, transAcc) %>%
  as.matrix() %>%
  Hmisc::rcorr()

CorrMatrixP <- CorrMatrix$P < .05

CorrMatrix <- CorrMatrix$r

stats::cor.test(AcousticData$VSA_b, AcousticData$vowel_ED_b, method = "pearson")

    Pearson's product-moment correlation

data:  AcousticData$VSA_b and AcousticData$vowel_ED_b
t = 6.5285, df = 38, p-value = 1.076e-07
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.5372669 0.8468014
sample estimates:
      cor 
0.7270881 
stats::cor.test(AcousticData$Hull_b, AcousticData$Hull_bVSD_25, method = "pearson")

    Pearson's product-moment correlation

data:  AcousticData$Hull_b and AcousticData$Hull_bVSD_25
t = 9.4906, df = 38, p-value = 1.43e-11
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7135136 0.9119080
sample estimates:
     cor 
0.838625 
write.csv(CorrMatrix, file = "Tables/Correlation Matrix.csv")
rm(CorrMatrix)

Research Q1: Modeling Intelligibility

Orthographic Transcriptions

Model 1


# Specifying Model 1

OT_Model1 <- lm(transAcc ~ Hull_bVSD_25, data = AcousticData)

## Model 1 Assumptions 

performance::check_model(OT_Model1)


## Model 1 Summary

summary(OT_Model1)

Call:
lm(formula = transAcc ~ Hull_bVSD_25, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.896 -14.090   5.996  17.470  36.105 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   48.2973     9.7372   4.960  1.5e-05 ***
Hull_bVSD_25   0.6417     0.5663   1.133    0.264    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.83 on 38 degrees of freedom
Multiple R-squared:  0.03268,   Adjusted R-squared:  0.007224 
F-statistic: 1.284 on 1 and 38 DF,  p-value: 0.2643

Model 2


## Specifying Model 2

OT_Model2 <- lm(transAcc ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

## Model 2 Assumption Check

performance::check_model(OT_Model2)


## Model 2 Summary

summary(OT_Model2)

Call:
lm(formula = transAcc ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-48.854 -13.962   5.567  16.758  36.257 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   47.3374    10.3316   4.582 5.09e-05 ***
Hull_bVSD_25   0.8045     0.7781   1.034    0.308    
Hull_bVSD_75  -0.7188     2.3225  -0.309    0.759    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.11 on 37 degrees of freedom
Multiple R-squared:  0.03518,   Adjusted R-squared:  -0.01698 
F-statistic: 0.6745 on 2 and 37 DF,  p-value: 0.5156
## Model 1 and Model 2 Comparison

anova(OT_Model1, OT_Model2)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_25
Model 2: transAcc ~ Hull_bVSD_25 + Hull_bVSD_75
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     38 21570                           
2     37 21514  1    55.696 0.0958 0.7587

Model 3a


## Specifying Model 3

OT_Model3a <- lm(transAcc ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(OT_Model3a)

performance::check_collinearity(OT_Model3a)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 2.00         1.41      0.50
       Hull_b 3.65         1.91      0.27

Moderate Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_25 5.33         2.31      0.19
## Model 3 Summary

summary(OT_Model3a)

Call:
lm(formula = transAcc ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, 
    data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-56.706 -13.157   7.018  17.957  29.990 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   31.0806    14.4916   2.145   0.0388 *
Hull_bVSD_25  -0.8439     1.2984  -0.650   0.5199  
Hull_bVSD_75   0.3159     2.3714   0.133   0.8948  
Hull_b         1.2941     0.8247   1.569   0.1253  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.65 on 36 degrees of freedom
Multiple R-squared:  0.09695,   Adjusted R-squared:  0.0217 
F-statistic: 1.288 on 3 and 36 DF,  p-value: 0.2932
## Model 2 and Model 3 Comparison

anova(OT_Model2, OT_Model3a)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_25 + Hull_bVSD_75
Model 2: transAcc ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     37 21514                           
2     36 20137  1    1377.5 2.4626 0.1253

Model 3b


## Specifying Model 3

OT_Model3b <- lm(transAcc ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(OT_Model3b)

performance::check_collinearity(OT_Model3b)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.26         1.12      0.79
## Model 3 Summary

summary(OT_Model3b)

Call:
lm(formula = transAcc ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-54.371 -12.860   5.038  17.725  31.609 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   33.2337    13.9973   2.374   0.0229 *
Hull_bVSD_75  -0.6193     1.8702  -0.331   0.7424  
Hull_b         0.8605     0.4809   1.789   0.0818 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.47 on 37 degrees of freedom
Multiple R-squared:  0.08635,   Adjusted R-squared:  0.03697 
F-statistic: 1.749 on 2 and 37 DF,  p-value: 0.1881

Model 4


## Specifying Model 4

OT_Model4 <- lm(transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

## Model 4 Assumption Check

performance::check_model(OT_Model4)

performance::check_collinearity(OT_Model4)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.68         1.30      0.60
        VSA_b 1.45         1.20      0.69
## Model 4 Summary

summary(OT_Model4)

Call:
lm(formula = transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.705 -12.573   3.108  14.504  35.215 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)   
(Intercept)   30.7726    12.7686   2.410  0.02119 * 
Hull_bVSD_75  -0.8216     1.7037  -0.482  0.63256   
Hull_b         0.1202     0.5049   0.238  0.81322   
VSA_b          5.8426     1.9859   2.942  0.00567 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21.36 on 36 degrees of freedom
Multiple R-squared:  0.2634,    Adjusted R-squared:  0.2021 
F-statistic: 4.292 on 3 and 36 DF,  p-value: 0.01092
## Model 3 and Model 4 Comparison

anova(OT_Model3b, OT_Model4)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_75 + Hull_b
Model 2: transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b
  Res.Df   RSS Df Sum of Sq      F   Pr(>F)   
1     37 20373                                
2     36 16424  1    3948.9 8.6555 0.005673 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Model 5


## Specifying Model 5

OT_Model5 <- lm(transAcc ~ Hull_bVSD_75 + VSA_b + vowel_ED_b, data = AcousticData)

## Model 4 Assumption Check

performance::check_model(OT_Model5)

performance::check_collinearity(OT_Model5)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.10         1.05      0.91
        VSA_b 2.30         1.52      0.43
   vowel_ED_b 2.15         1.47      0.46
## Model 4 Summary

summary(OT_Model5)

Call:
lm(formula = transAcc ~ Hull_bVSD_75 + VSA_b + vowel_ED_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-46.501 -11.965   2.561  14.356  33.849 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   24.4273    20.1254   1.214   0.2327  
Hull_bVSD_75  -0.5814     1.5872  -0.366   0.7163  
VSA_b          5.2219     2.4990   2.090   0.0438 *
vowel_ED_b     6.0028    12.7240   0.472   0.6399  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21.31 on 36 degrees of freedom
Multiple R-squared:  0.2668,    Adjusted R-squared:  0.2057 
F-statistic: 4.367 on 3 and 36 DF,  p-value: 0.0101
## Model 3 and Model 4 Comparison

anova(OT_Model4, OT_Model5)
Analysis of Variance Table

Model 1: transAcc ~ Hull_bVSD_75 + Hull_b + VSA_b
Model 2: transAcc ~ Hull_bVSD_75 + VSA_b + vowel_ED_b
  Res.Df   RSS Df Sum of Sq F Pr(>F)
1     36 16424                      
2     36 16349  0    75.229         

Final Model


## Specifying Final Model

OT_Model_final <- lm(transAcc ~ VSA_b, data = AcousticData)

## Final Model Assumption Check

performance::check_model(OT_Model_final)


## Final Model Summary

summary(OT_Model_final)

Call:
lm(formula = transAcc ~ VSA_b, data = AcousticData)

Residuals:
   Min     1Q Median     3Q    Max 
-46.72 -12.69   2.97  14.37  35.39 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   32.508      7.857   4.138 0.000187 ***
VSA_b          5.872      1.613   3.641 0.000807 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 20.86 on 38 degrees of freedom
Multiple R-squared:  0.2586,    Adjusted R-squared:  0.2391 
F-statistic: 13.25 on 1 and 38 DF,  p-value: 0.0008068
confint(OT_Model_final)
                2.5 %    97.5 %
(Intercept) 16.602765 48.413532
VSA_b        2.606927  9.137097

VAS Models

Model 1


# Specifying Model 1

VAS_Model1 <- lm(VAS ~ Hull_bVSD_25, data = AcousticData)

## Model 1 Assumptions 

performance::check_model(VAS_Model1)


## Model 1 Summary

summary(VAS_Model1)

Call:
lm(formula = VAS ~ Hull_bVSD_25, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.625 -16.684   8.462  19.440  37.352 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   42.6328    10.7512   3.965 0.000313 ***
Hull_bVSD_25   0.5877     0.6253   0.940 0.353236    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.31 on 38 degrees of freedom
Multiple R-squared:  0.02272,   Adjusted R-squared:  -0.003001 
F-statistic: 0.8833 on 1 and 38 DF,  p-value: 0.3532

Model 2


## Specifying Model 2

VAS_Model2 <- lm(VAS ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

## Model 2 Assumption Check

performance::check_model(VAS_Model2)


## Model 2 Summary

summary(VAS_Model2)

Call:
lm(formula = VAS ~ Hull_bVSD_25 + Hull_bVSD_75, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-47.850 -16.576   8.382  19.448  37.237 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   42.3384    11.4211   3.707 0.000684 ***
Hull_bVSD_25   0.6376     0.8602   0.741 0.463195    
Hull_bVSD_75  -0.2204     2.5674  -0.086 0.932036    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.66 on 37 degrees of freedom
Multiple R-squared:  0.02291,   Adjusted R-squared:  -0.0299 
F-statistic: 0.4338 on 2 and 37 DF,  p-value: 0.6513
## Model 1 and Model 2 Comparison

anova(VAS_Model1, VAS_Model2)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_25
Model 2: VAS ~ Hull_bVSD_25 + Hull_bVSD_75
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     38 26296                           
2     37 26291  1     5.239 0.0074  0.932

Model 3a


## Specifying Model 3

VAS_Model3a <- lm(VAS ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(VAS_Model3a)

performance::check_collinearity(VAS_Model3a)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 2.00         1.41      0.50
       Hull_b 3.65         1.91      0.27

Moderate Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_25 5.33         2.31      0.19
## Model 3 Summary

summary(VAS_Model3a)

Call:
lm(formula = VAS ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-56.444 -18.989   6.121  18.036  32.281 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept)   25.0400    16.0599   1.559    0.128
Hull_bVSD_25  -1.1164     1.4389  -0.776    0.443
Hull_bVSD_75   0.8805     2.6280   0.335    0.740
Hull_b         1.3770     0.9139   1.507    0.141

Residual standard error: 26.21 on 36 degrees of freedom
Multiple R-squared:  0.08087,   Adjusted R-squared:  0.00428 
F-statistic: 1.056 on 3 and 36 DF,  p-value: 0.3799
## Model 2 and Model 3 Comparison

anova(VAS_Model2, VAS_Model3a)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_25 + Hull_bVSD_75
Model 2: VAS ~ Hull_bVSD_25 + Hull_bVSD_75 + Hull_b
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     37 26291                           
2     36 24731  1    1559.6 2.2702 0.1406

Model 3b

This model removes VSD25 because of it’s high VIF value > 5.


## Specifying Model 3b

VAS_Model3b <- lm(VAS ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

## Model 3 Assumption Check

performance::check_model(VAS_Model3b)

performance::check_collinearity(VAS_Model3b)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.26         1.12      0.79
## Model 3 Summary

summary(VAS_Model3b)

Call:
lm(formula = VAS ~ Hull_bVSD_75 + Hull_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-53.356 -19.394   8.036  21.298  33.412 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)   27.8884    15.5503   1.793   0.0811 .
Hull_bVSD_75  -0.3567     2.0777  -0.172   0.8646  
Hull_b         0.8034     0.5343   1.504   0.1412  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 26.07 on 37 degrees of freedom
Multiple R-squared:  0.0655,    Adjusted R-squared:  0.01499 
F-statistic: 1.297 on 2 and 37 DF,  p-value: 0.2855

Model 4


## Specifying Model 4

VAS_Model4 <- lm(VAS ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

## Model 4 Assumption Check

performance::check_model(VAS_Model4)

performance::check_collinearity(VAS_Model4)
# Check for Multicollinearity

Low Correlation

         Term  VIF Increased SE Tolerance
 Hull_bVSD_75 1.26         1.12      0.79
       Hull_b 1.68         1.30      0.60
        VSA_b 1.45         1.20      0.69
## Model 4 Summary

summary(VAS_Model4)

Call:
lm(formula = VAS ~ Hull_bVSD_75 + Hull_b + VSA_b, data = AcousticData)

Residuals:
   Min     1Q Median     3Q    Max 
-45.56 -15.17   6.40  16.64  42.62 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)   
(Intercept)   2.522e+01  1.426e+01   1.768  0.08553 . 
Hull_bVSD_75 -5.762e-01  1.903e+00  -0.303  0.76382   
Hull_b        5.056e-05  5.640e-01   0.000  0.99993   
VSA_b         6.340e+00  2.218e+00   2.858  0.00705 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.86 on 36 degrees of freedom
Multiple R-squared:  0.2383,    Adjusted R-squared:  0.1748 
F-statistic: 3.754 on 3 and 36 DF,  p-value: 0.01916
## Model 3 and Model 4 Comparison

anova(VAS_Model3b, VAS_Model4)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_75 + Hull_b
Model 2: VAS ~ Hull_bVSD_75 + Hull_b + VSA_b
  Res.Df   RSS Df Sum of Sq      F   Pr(>F)   
1     37 25145                                
2     36 20495  1    4649.8 8.1674 0.007046 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Model 5


## Specifying Model 5

VAS_Model5 <- lm(VAS ~ Hull_bVSD_75 + Hull_b + VSA_b + vowel_ED_b, data = AcousticData)

## Model 5 Assumption Check

performance::check_model(VAS_Model5)


## Model 5 Summary

summary(VAS_Model5)

Call:
lm(formula = VAS ~ Hull_bVSD_75 + Hull_b + VSA_b + vowel_ED_b, 
    data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-44.407 -13.917   7.397  16.408  41.322 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept)  16.61280   23.81590   0.698    0.490  
Hull_bVSD_75 -0.40875    1.95955  -0.209    0.836  
Hull_b       -0.05465    0.58294  -0.094    0.926  
VSA_b         5.49348    2.91674   1.883    0.068 .
vowel_ED_b    6.68540   14.72389   0.454    0.653  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.13 on 35 degrees of freedom
Multiple R-squared:  0.2428,    Adjusted R-squared:  0.1562 
F-statistic: 2.805 on 4 and 35 DF,  p-value: 0.04041
## Model 4 and Model 5 Comparison

anova(VAS_Model4, VAS_Model5)
Analysis of Variance Table

Model 1: VAS ~ Hull_bVSD_75 + Hull_b + VSA_b
Model 2: VAS ~ Hull_bVSD_75 + Hull_b + VSA_b + vowel_ED_b
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1     36 20495                           
2     35 20375  1    120.02 0.2062 0.6526

Final Model


## Specifying Final Model

VAS_Model_final <- lm(VAS ~ VSA_b, data = AcousticData)

## Final Model Assumption Check

performance::check_model(VAS_Model_final)


## Final Model Summary

summary(VAS_Model_final)

Call:
lm(formula = VAS ~ VSA_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-44.956 -15.943   6.754  17.153  43.062 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)   24.703      8.761   2.820  0.00760 **
VSA_b          6.163      1.798   3.427  0.00148 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.26 on 38 degrees of freedom
Multiple R-squared:  0.2361,    Adjusted R-squared:  0.216 
F-statistic: 11.74 on 1 and 38 DF,  p-value: 0.001482
confint(VAS_Model_final)
               2.5 %    97.5 %
(Intercept) 6.966936 42.438084
VSA_b       2.521887  9.803467

Research Q2: Relationship between OT and VAS

Model 1


# Specify Model

OT_VAS_model <- lm(transAcc ~ VAS*Etiology + VAS*Sex, data = AcousticData)

# Assumption Check

performance::check_model(OT_VAS_model)

# Model Results

summary(OT_VAS_model)

Final Linear Model


# Specify Final Model

OT_VAS_final <- lm(transAcc ~ VAS, data = AcousticData)

confint(OT_VAS_final)

# Model Results

summary(OT_VAS_final)

Corner Dispersion

Looking at corner dispersion as the sole predictor.


# Specify Final Model

OT_cornDisp <- lm(transAcc ~ vowel_ED_b, data = AcousticData)
summary(OT_cornDisp)

Call:
lm(formula = transAcc ~ vowel_ED_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-53.949 -10.348   4.268  14.982  25.903 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)    6.227     18.611   0.335  0.73977   
vowel_ED_b    25.564      8.946   2.857  0.00689 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21.98 on 38 degrees of freedom
Multiple R-squared:  0.1769,    Adjusted R-squared:  0.1552 
F-statistic: 8.165 on 1 and 38 DF,  p-value: 0.006891
VAS_cornDisp <- lm(VAS ~ vowel_ED_b, data = AcousticData)
summary(VAS_cornDisp)

Call:
lm(formula = VAS ~ vowel_ED_b, data = AcousticData)

Residuals:
    Min      1Q  Median      3Q     Max 
-52.146 -13.413   7.142  18.719  32.964 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)   -2.859     20.636  -0.139   0.8905  
vowel_ED_b    26.819      9.920   2.704   0.0102 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.37 on 38 degrees of freedom
Multiple R-squared:  0.1613,    Adjusted R-squared:  0.1393 
F-statistic:  7.31 on 1 and 38 DF,  p-value: 0.0102

Manuscript Tables

Descriptives Table

gtData <- AcousticData %>%
  rbind(.,AcousticData %>%
          dplyr::mutate(Etiology = "All Etiologies")) %>%
  rbind(.,AcousticData %>%
          rbind(.,AcousticData %>%
          dplyr::mutate(Etiology = "All Etiologies")) %>%
          dplyr::mutate(Sex = "All")) %>%
  dplyr::mutate(Sex = as.factor(Sex),
                Etiology = as.factor(Etiology)) %>%
  dplyr::group_by(Sex, Etiology) %>%
  dplyr::summarize(VSA_mean = mean(VSA_b, na.rm =T), VSA_sd = sd(VSA_b, na.rm = T),
                   Disp_mean = mean(vowel_ED_b, na.rm =T), Disp_sd = sd(vowel_ED_b, na.rm =T),
                   Hull_mean = mean(Hull_b, na.rm =T), Hull_sd = sd(Hull_b, na.rm =T),
                   VSD25_mean = mean(Hull_bVSD_25, na.rm =T), VSD25_sd = sd(Hull_bVSD_25, na.rm =T),
                   VSD50_mean = mean(Hull_bVSD_50, na.rm =T), VSD50_sd = sd(Hull_bVSD_50, na.rm =T),
                   VSD75_mean = mean(Hull_bVSD_75, na.rm =T), VSD75_sd = sd(Hull_bVSD_75, na.rm =T),
                   VAS_mean = mean(VAS, na.rm =T), VAS_sd = sd(VAS, na.rm =T),
                   OT_mean = mean(transAcc, na.rm =T), OT_sd = sd(transAcc, na.rm =T)) %>%
  pivot_longer(cols = VSA_mean:OT_sd, names_to = "Measure",
               values_to = "Value") %>%
  dplyr::mutate(Value = round(Value, digits = 2),
                meanSD = ifelse(grepl("_mean",Measure),"M","sd"),
                Measure = gsub("_mean","",Measure),
                Measure = gsub("_sd","",Measure),
                Etiology = paste(Etiology,meanSD, sep = "_"),
                Sex = case_when(
                  Sex == "All" ~ "All Speakers",
                  Sex == "M" ~ "Male Speakers",
                  Sex == "F" ~ "Female Speakers"
                )) %>%
  dplyr::select(!meanSD) %>%
  pivot_wider(names_from = Etiology, values_from = "Value") %>%
  dplyr::filter(Measure != "VSD50")
`summarise()` has grouped output by 'Sex'. You can override using the `.groups` argument.
gtData %>%
  gt::gt(
    rowname_col = "Measure",
    groupname_col = "Sex",
  ) %>%
  fmt_number(
    columns = 'All Etiologies_M':PD_sd,
    decimals = 2
  ) %>%
  tab_spanner(
    label = "All Etiologies",
    columns = c('All Etiologies_M', 'All Etiologies_sd')
  ) %>%
    tab_spanner(
    label = "ALS",
    columns = c(ALS_M, ALS_sd)
  ) %>%
  tab_spanner(
    label = "PD",
    columns = c(PD_M, PD_sd)
  ) %>%
  tab_spanner(
    label = "HD",
    columns = c(HD_M, HD_sd)
  ) %>%
  tab_spanner(
    label = "Ataxic",
    columns = c(Ataxic_M, Ataxic_sd)
  ) %>%
  gt::cols_move_to_start(
    columns = c('All Etiologies_M','All Etiologies_sd')
  ) %>%
  row_group_order(
    groups = c("All Speakers", "Female Speakers", "Male Speakers")
    ) %>%
  cols_label(
     'All Etiologies_M' = "M",
     'All Etiologies_sd' = "SD",
     ALS_M = "M",
     ALS_sd = "SD",
     PD_M = "M",
     PD_sd = "SD",
     HD_M = "M",
     HD_sd = "SD",
     Ataxic_M = "M",
     Ataxic_sd = "SD"
  ) %>%
  gtsave("DescriptivesTable.html", path = "Tables")

OT Model

sjPlot::tab_model(OT_Model1,
                  OT_Model2,
                  OT_Model3b,
                  OT_Model4,
                  OT_Model5,
                  OT_Model_final,
                  show.ci = F,
                  p.style = "stars",
                  file = "Tables/OT Models.html")

VAS Model

sjPlot::tab_model(VAS_Model1,
                  VAS_Model2,
                  VAS_Model3,
                  VAS_Model4,
                  VAS_Model5,
                  VAS_Model_final,
                  show.ci = F,
                  p.style = "stars",
                  file = "Tables/VAS Models.html")

OT vs. VAS

sjPlot::tab_model(OT_VAS_model,OT_VAS_final,
                  show.ci = F,
                  show.reflvl = TRUE,
                  p.style = "stars",
                  file = "Tables/OT and VAS Comparison.html")

Manuscript Figures

Example Measures

formantColor <- "grey"
formantAlpha <- .95
lineColor <- "white"
lineAlpha <- .8

vowelData <- rio::import("Prepped Data/Vowel Data.csv") %>%
  dplyr::filter(Speaker == "AF8")

  Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))
  
  Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
  Formants_PRAAT <- Formants_PRAAT %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    dplyr::filter(mDist_sd < 2) %>%
    dplyr::select(!c(F1_mad, F2_mad, mDist, mDist_sd)) %>%
    dplyr::mutate(F1_z = scale(F1_Hz, center = TRUE),
                  F2_z = scale(F2_Hz, center = TRUE),
                  F3_z = scale(F3_Hz, center = TRUE),
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz))
  
  rm(Pitch_PRAAT)
  
  
## Corner Dispersion ----
  wedge <- vowelData %>%
    dplyr::group_by(Vowel) %>%
    dplyr::summarize(mean_F1 = mean(F1_tempMid),
              mean_F2 = mean(F2_tempMid),
              mean_F1_z = mean(F1_z_tempMid),
              mean_F2_z = mean(F2_z_tempMid),
              mean_F1_b = mean(F1_b_tempMid),
              mean_F2_b = mean(F2_b_tempMid)) %>%
    dplyr::filter(Vowel == "v")
    
  corner_dis <- vowelData %>%
    dplyr::filter(Vowel != "v") %>%
    dplyr::group_by(Vowel) %>%
    dplyr::summarize(mean_F1 = mean(F1_tempMid),
              mean_F2 = mean(F2_tempMid),
              mean_F1_z = mean(F1_z_tempMid),
              mean_F2_z = mean(F2_z_tempMid),
              mean_F1_b = mean(F1_b_tempMid),
              mean_F2_b = mean(F2_b_tempMid)) %>%
    dplyr::mutate(Vowel_ED = sqrt((mean_F1-wedge$mean_F1)^2 + (mean_F2-wedge$mean_F2)^2),
                  Vowel_ED_z = sqrt((mean_F1_z-wedge$mean_F1_z)^2 + (mean_F2_z-wedge$mean_F2_z)^2),
                  Vowel_ED_b = sqrt((mean_F1_b-wedge$mean_F1_b)^2 + (mean_F2_b-wedge$mean_F2_b)^2))

    
# Plot Corner Dispersion
      # Changing to IPA symbols
      corner_dis <- corner_dis %>%
        dplyr::mutate(Vowel = dplyr::case_when(
          Vowel == "ae" ~ "æ",
          TRUE ~ Vowel
        ))
      
      wedge <- wedge %>%
        dplyr::mutate(Vowel = case_when(
          Vowel == "v" ~ "ʌ",
          TRUE ~ Vowel
        ))
      
      CDplot <- ggplot(aes(x=F2_b,
                           y=F1_b),
                       data = Formants_PRAAT,
                       inherit.aes = FALSE) + 
      geom_point(shape = 21,
                 alpha = formantAlpha,
                 color = formantColor) + 
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "i") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "a") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "æ") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_line(aes(x = mean_F2_b,
                    y = mean_F1_b),
                data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  dplyr::filter(Vowel == "u") %>%
                  rbind(.,wedge),
                color = lineColor,
                size = 1.5,
                alpha = lineAlpha) +
      geom_point(aes(x = mean_F2_b,
                     y = mean_F1_b,
                     color = Vowel),
                 data = corner_dis %>%
                  dplyr::select(Vowel:mean_F2_b) %>%
                  rbind(.,wedge),
                 inherit.aes = FALSE,
                 size = 5) +
      scale_y_reverse() +
      scale_x_reverse() +
      theme_classic() + labs(title = paste("Corner Dispersion")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1) +
          scale_color_manual(values = c("a" = "#1AAD77",
                                        "æ" = "#1279B5",
                                        "i" = "#FFBF00",
                                        "u" = "#FD7853",
                                        "ʌ" = "#BF3178"))
    CDplot

    
      rm(corner_dis, wedge)
      
## Vowel Space Area ----
  VSA_coords <- vowelData %>%
    dplyr::filter(Vowel != "v") %>%
    dplyr::group_by(Vowel) %>%
    dplyr::summarize(mean_F1 = mean(F1_tempMid),
              mean_F2 = mean(F2_tempMid),
              mean_F1_z = mean(F1_z_tempMid),
              mean_F2_z = mean(F2_z_tempMid),
              mean_F1_b = mean(F1_b_tempMid),
              mean_F2_b = mean(F2_b_tempMid)) 
  
### Plotting VSA
    VSA_coords <- VSA_coords %>%
        dplyr::mutate(Vowel = case_when(
          Vowel == "ae" ~ "æ",
          TRUE ~ Vowel
        ))
    
    VSAplot <- ggplot(aes(x = F2_b,
                          y = F1_b),
                      data = Formants_PRAAT,
                      inherit.aes = FALSE) + 
      geom_point(shape = 21,
                 alpha = formantAlpha,
                 color = formantColor) + 
      geom_polygon(aes(x = mean_F2_b,
                       y = mean_F1_b),
                   data = VSA_coords,
                   alpha = lineAlpha,
                   color = lineColor,
                   fill=NA,
                   size = 1.5) +
      geom_point(aes(x = mean_F2_b,
                     y = mean_F1_b,
                     color = Vowel),
                 data = VSA_coords,
                 inherit.aes = FALSE,
                 size = 5) +
      scale_y_reverse() +
      scale_x_reverse() +
      guides(color = FALSE) +
      theme_classic() + labs(title = "VSA") + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1) +
                scale_color_manual(values = c("a" = "#1AAD77",
                                        "æ" = "#1279B5",
                                        "i" = "#FFBF00",
                                        "u" = "#FD7853"))
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
    VSAplot

  
  rm(VSA_coords)
  
## Hull ----
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21,
                 alpha = formantAlpha,
                 color = formantColor) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        scale_y_reverse() +
        scale_x_reverse() +
        theme_classic() + labs(title = expression("VSA"[Hull])) +
                                 xlab("F2 (Bark)") +
                                 ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1)
      hullPlot

    
  
## Vowel Space Density ----

# Bark Normalized Density ----
# selecting the bandwidth
H_hpi <- ks::Hpi(x = Formants_PRAAT[,c("F2_b","F1_b")], pilot = "samse", pre = "scale", binned = T)

# compute 2d kde
k <- kde(x = Formants_PRAAT[,c("F2_b","F1_b")],
         H = H_hpi,
         binned = T,
         gridsize = 250)

#density <- k[["estimate"]]

# Before we can plot the density estimate we need to melt it into long format
mat.melted <- data.table::melt(k$estimate)
The melt generic in data.table has been passed a matrix and will attempt to redirect to the relevant reshape2 method; please note that reshape2 is deprecated, and this redirection is now deprecated as well. To continue using melt methods from reshape2 while both libraries are attached, e.g. melt.list, you can prepend the namespace like reshape2::melt(k$estimate). In the next version, this warning will become an error.
names(mat.melted) <- c("x", "y", "density")

# We need to add two more colums to preserve the axes units
mat.melted$F2.b <- rep(k$eval.points[[1]], times = nrow(k$estimate))
mat.melted$F1.b <- rep(k$eval.points[[2]], each = nrow(k$estimate))
mat.melted$density <- scales::rescale(mat.melted$density, to = c(0, 1))

# VSD - 25
nVSD_25 <- mat.melted %>%
  dplyr::filter(density > .25) %>%
  dplyr::select(F2.b,F1.b, density) %>%
  dplyr::rename(Density = density)

convexCoords <- nVSD_25 %>%
  dplyr::select(F2.b, F1.b) %>%
  as.matrix() %>%
  #grDevices::xy.coords() %>%
  grDevices::chull()
nconvex_25 <- nVSD_25 %>%
  slice(convexCoords)

# VSD - 75
nVSD_75 <- mat.melted %>%
  dplyr::filter(density > .75) %>%
  dplyr::select(F2.b,F1.b, density) %>%
  dplyr::rename(Density = density)

convexCoords <- nVSD_75 %>%
  dplyr::select(F2.b, F1.b) %>%
  as.matrix() %>%
  grDevices::chull()
nconvex_75 <- nVSD_75 %>%
  slice(convexCoords)

# Plotting Z Normalized VSD 
    rf <- colorRampPalette(rev(RColorBrewer::brewer.pal(11, "Spectral")))
    r <- rf(32)
    
    plotData <- mat.melted %>%
                        dplyr::rename(Density = density) %>%
                        dplyr::mutate(VSDlabel = dplyr::case_when(
                          Density < .25 ~ "none",
                          Density > .25 && Density < .75 ~ "VSD25",
                          TRUE ~ "VSD75"
                        ))
geom.text.size <- 2
    VSDplot <- ggplot(data = plotData,
                      aes(x = F2.b,
                          y = F1.b,
                          fill = Density)) + 
      geom_tile() + 
      scale_fill_viridis_c() +
      scale_x_reverse(expand = c(0, 0), 
                      breaks = round(seq(min(mat.melted$F2.b), 
                                         max(mat.melted$F2.b), by = 2))) +
      scale_y_reverse(expand = c(0, 0),
                      breaks = round(seq(min(mat.melted$F1.b),
                                         max(mat.melted$F1.b), by = 2))) + 
      ylab("F1 (Bark)") + xlab("F2 (Bark)") +
      labs(title = "VSD") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1) +
      geom_polygon(data = nconvex_25, alpha = lineAlpha, color = lineColor, size = 1.5, fill = NA, linetype = 2) +
      geom_polygon(data = nconvex_75, alpha = lineAlpha, color = lineColor, size = 1.5, fill = NA, linetype = 1) +
    # VSD 25 Label
      annotate(geom = "curve",
               x = 6.9, y = 1.7+.5,
               xend = 8.5, yend = 3.5,
               curvature = -.3,
               arrow = arrow(length = unit(2, "mm")),
               color = "white") +
      annotate(geom = "text",
               x = 7.5, y = 1.7,
               label = deparse(bquote(VSD[25])),
               hjust = "center",
               color = "white",
               parse=TRUE) +
    # VSD 75 Label
      annotate(geom = "curve",
               x = 7.5, y = 7.5-.5,
               xend = 11.35, yend = 5.5,
               curvature = .3,
               arrow = arrow(length = unit(2, "mm")),
               color = "white") +
      annotate(geom = "text",
               x = 7, y = 7.5,
               label = deparse(bquote(VSD[75])),
               hjust = "center",
               color = "white",
               parse = TRUE)
     VSDplot


# Combined Plot
     
     row1 <- VSAplot + CDplot +
        patchwork::plot_layout(guides = 'collect',
                         ncol = 2) & theme(legend.position = 'right')
     row2 <- hullPlot + VSDplot +
        patchwork::plot_layout(guides = 'collect',
                         ncol = 2) & theme(legend.position = 'right')
     
     measuresPlot <- row1 / row2 + patchwork::plot_layout(heights = c(1/2, 1/2), byrow = FALSE)
     measuresPlot
     
     rm(row1, row2)

ggsave(filename = "Plots/Measures.png",
       plot = measuresPlot,
       height = 5.5,
       width = 6,
       scale = .8)

Filtering Process

formantAlpha <- .20
myPal <- c("#1279B5","#2D2D37")

Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data/", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
  # Raw Formants ----
  f1 <- ggplot(aes(x=F2_b,
                   y=F1_b),
               data = Formants_PRAAT) + 
      geom_point(shape = 21, color = myPal[2]) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() + labs(title = paste("Raw Formant\nValues")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Step #1: Voiced Segments ----
    plotData <- Formants_PRAAT %>%
                   dplyr::mutate(isOutlier = case_when(
                     is.na(Pitch) ~ "Removed",
                     TRUE ~ "Retained"
                   ))
    f2 <- ggplot(data = plotData,
                 aes(x = F2_b,
                     y = F1_b,
                     color = isOutlier)) + 
      geom_point(shape = 21, data = plotData %>%
                   dplyr::filter(isOutlier == "Removed")) +
      geom_point(shape = 21, data = plotData %>%
             dplyr::filter(isOutlier == "Retained")) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() + labs(title = paste("Voiced Segments")) +
      xlab("F2 (Bark)") +
      ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Step 2: MAD ----
    plotData <- Formants_PRAAT %>%
      dplyr::filter(!is.na(Pitch)) %>%
      dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                    F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5,
                    isOutlier = case_when(
                      F1_mad == TRUE | F2_mad == TRUE ~ "Removed",
                      TRUE ~ "Retained"
               ))
    
    f3 <- ggplot(data = plotData,
                 aes(x = F2_b,
                     y = F1_b,
                     color = isOutlier)) + 
      geom_point(shape = 21, data = plotData %>%
                   dplyr::filter(isOutlier == "Removed")) +
      geom_point(shape = 21, data = plotData %>%
             dplyr::filter(isOutlier == "Retained")) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() +
      labs(title = paste("Median Absolute\nDeviation")) +
      xlab("F2 (Bark)") +
      ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Step 3: Mahalanhobis Distance ----
  plotData <- Formants_PRAAT %>%
      dplyr::filter(!is.na(Pitch)) %>%
      dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                    F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
      dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
      dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T)),
                  isOutlier = case_when(
                    mDist_sd < 2 ~ "Retained",
                    TRUE ~ "Removed"
                  ))
    
    f4 <- ggplot(data = plotData,
                 aes(x = F2_b,
                     y = F1_b,
                     color = isOutlier)) + 
      geom_point(shape = 21, data = plotData %>%
                   dplyr::filter(isOutlier == "Removed")) +
      geom_point(shape = 21, data = plotData %>%
             dplyr::filter(isOutlier == "Retained")) +
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      scale_color_manual(values = myPal) +
      theme_classic() + labs(title = paste("Mahalanobis\nDistance")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1,
            legend.title = element_blank(),
            legend.text = element_text(size=12))
    
# Final Formants ----
    plotData <- Formants_PRAAT %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    dplyr::filter(mDist_sd < 2)
    
    f5 <- ggplot(aes(x=F2_b,
                     y=F1_b),
                       data = plotData,
                       inherit.aes = FALSE) + 
      geom_point(shape = 21, color = myPal[2]) + 
      scale_y_reverse(limits = c(16,0)) +
      scale_x_reverse(limits = c(19,3)) +
      theme_classic() + labs(title = paste("Final Formant\nTrajectories")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
      theme(plot.title = element_text(hjust = 0.5),
            aspect.ratio = 1, legend.title = element_blank())
    
# Comibing plots
    filteredPlot <- f1 + f2 + f3 + f4 + f5 + patchwork::guide_area() +
      patchwork::plot_layout(guides = 'collect',
                         ncol = 3) +
      patchwork::plot_annotation(tag_levels = 'A')
    filteredPlot
    
    ggsave(plot = filteredPlot, "Plots/Filtered Formants.png",
           height = 6,
           width = 8,
           units = "in",
           scale = .9)

NA

OT vs. VAS

plotData_Int <- AcousticData %>%
  dplyr::filter(!grepl("_rel", Speaker)) %>%
  dplyr::group_by(Speaker) %>%
  dplyr::mutate(segMin = base::min(VAS, transAcc),
                segMax = base::max(VAS, transAcc),
                ratingAvg = mean(VAS, transAcc, na.rm = T),
                Speaker = as.factor(Speaker),
                Etiology = case_when(
                  Etiology == "Ataxic" ~ "Ataxia",
                  TRUE ~ as.character(Etiology)
                ),
                Etiology = as.factor(Etiology)) %>%
  arrange(segMax)

my_pal <- c("#f26430", "#272D2D","#256eff")
# With a bit more style
plot_Int <- ggplot(plotData_Int) +
  geom_segment(aes(x = fct_inorder(Speaker),
                   xend = Speaker,
                   y = segMin,
                   yend = segMax,
                   color = Etiology)) +
  geom_point(aes(x = Speaker,
                 y = VAS,
                 color = Etiology),
             #color = my_pal[1],
             size = 3,
             shape = 19) +
  geom_point(aes(x = Speaker,
                 y = transAcc,
                 color = Etiology),
             #color = my_pal[2],
             size = 3,
             shape = 15) +
  coord_flip()+
  theme_classic() +
  theme(
    legend.position = "none",
    panel.border = element_blank(),
  ) +
  xlab("") +
  ylab("Speech Intelligibility") +
  ggtitle("Speech Intelligibility") +
  ylim(c(0,100))


myPal <- c("#1AAD77", "#1279B5", "#FFBF00", "#FD7853", "#BF3178")
myShapes <- c(16, 18, 17, 15)

OT_VASscatter <- ggplot(plotData_Int,
                  aes(x = VAS,
                      y = transAcc,
                      color = Etiology,
                      shape = Etiology,
                      linetype = Etiology)) +
  geom_point() +
  geom_smooth(method = "lm", se = F) +
  geom_abline(intercept = 0, slope = 1) +
  coord_cartesian(xlim = c(0,100), ylim = c(0,100)) +
  labs(x = "Intelligibility (VAS)", y = "Intelligibility (OT)") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myShapes) +
  theme_classic() +
  theme(aspect.ratio=1,
        legend.position="right")


ggsave(filename = "Plots/OT and VAS Scatterplot.png",
       plot = OT_VASscatter,
       height = 3.25,
       width = 4,
       units = "in",
       scale = 1)

rm(scatter1, scatter2, combinedScatter)

Model Scatterplots

modelFigureData <- AcousticData %>%
  dplyr::filter(!grepl("_rel",Speaker)) %>%
  dplyr::select(Speaker, Etiology, Sex, VSA_b, vowel_ED_b, Hull_b, Hull_bVSD_25, Hull_bVSD_75, VAS, transAcc) %>%
  dplyr::mutate(Speaker = as.factor(Speaker),
                Etiology = as.factor(Etiology),
                Sex = as.factor(Sex)) %>%
  tidyr::pivot_longer(cols = VAS:transAcc, names_to = "IntType", values_to = "Int") %>%
  dplyr::mutate(IntType = case_when(
    IntType == "transAcc" ~ "OT",
    TRUE ~ "VAS"
  ),
                IntType = as.factor(IntType))

ylabel <- "Intelligibility"
myPal <- c("#2D2D37", "#1279B5")
myPalShape <- c(19, 1)

VSA <- modelFigureData %>%
  ggplot() +
  aes(x = VSA_b,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSA (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        aspect.ratio=1) +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

disp <- modelFigureData %>%
  ggplot() +
  aes(x = vowel_ED_b,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab("Corner Dispersion (Bark)") +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

Hull <- modelFigureData %>%
  ggplot() +
  aes(x = Hull_b,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSA"[Hull]*" (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) + theme(legend.position = "none") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

vsd25 <- modelFigureData %>%
  ggplot() +
  aes(x = Hull_bVSD_25,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSD"[25]*" (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) + theme(legend.position = "none") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

vsd75 <- modelFigureData %>%
  ggplot() +
  aes(x = Hull_bVSD_75,
      y = Int,
      color = IntType,
      shape = IntType,
      linetype = IntType) +
  geom_point() +
  geom_smooth(method = "lm", se = T, fill = "light grey") +
  geom_smooth(method = "lm", se = F) +
  xlab(expression("VSD"[75]*" (Bark"^2*")")) +
  ylab(ylabel) +
  coord_cartesian(ylim = c(0,100)) +
  theme_classic() +
  theme(aspect.ratio=1) + theme(legend.position = "none") +
  scale_color_manual(values = myPal) +
  scale_shape_manual(values = myPalShape) +
  labs(color="Intelligibility Type",
       shape = "Intelligibility Type",
       linetype = "Intelligibility Type")

# Creating OT Scatterplot Figure

scatter <- VSA  + disp + patchwork::guide_area() + Hull + vsd25 + vsd75 +
  patchwork::plot_layout(guides = 'collect',
                         ncol = 3) & theme(legend.position = "right")
scatter 

ggsave("Plots/ModelFigure.png", scatter,
       height = 4,
       width = 6,
       units = "in",
       scale = 1.1)

Filtering at Different Levels

text_x <- 12.5
text_y <- 8.5
xlims <- c(16,5)
ylims <- c(9,1)
# Hull - 2 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 2)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_2 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("2 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_2

      
# Hull - 2.5 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 2.5)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_2.5 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("2.5 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_2.5

      
# Hull - 3 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 3)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_3 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("3 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_3

      
# Hull - 1.5 SD ----
Pitch_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = ".Pitch", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = F) %>%
    dplyr::rename(Pitch = V1) %>%
    dplyr::mutate(Pitch = gsub("--undefined--",NA,Pitch),
                  Pitch = as.numeric(Pitch))

Formants_PRAAT <- list.files(path = paste("Prepped Data/Example Data", sep = ""), 
                              pattern = "_Formant", ignore.case = T) %>%
    paste("Prepped Data/Example Data/",., sep = "") %>%
    read.delim(., header = T) %>%
    dplyr::select(!c(nformants, B1.Hz., B2.Hz., B3.Hz., F4.Hz., B4.Hz., F5.Hz., B5.Hz.)) %>%
    dplyr::rename(Time_s = time.s.,
                  F1_Hz = F1.Hz.,
                  F2_Hz = F2.Hz.,
                  F3_Hz = F3.Hz.) %>%
    dplyr::mutate(F1_Hz = ifelse(F1_Hz == 0, NA, F1_Hz),
                  F2_Hz = ifelse(F2_Hz == 0, NA, F2_Hz),
                  F3_Hz = ifelse(F3_Hz == 0, NA, F3_Hz)) %>%
    dplyr::mutate(F1_Hz = as.numeric(F1_Hz),
                  F2_Hz = as.numeric(F2_Hz),
                  F3_Hz = suppressWarnings(as.numeric(F3_Hz)),
                  Time_ms = Time_s / 1000,
                  F1_kHz = F1_Hz / 1000,
                  F2_kHz = F2_Hz / 1000,
                  F3_kHz = F3_Hz / 1000,
                  F1_b = emuR::bark(F1_Hz),
                  F2_b = emuR::bark(F2_Hz),
                  F3_b = emuR::bark(F3_Hz)) %>%
    dplyr::select(!Time_s) %>%
    dplyr::relocate(Time_ms, .before = F1_Hz) %>%
    cbind(.,Pitch_PRAAT) %>%
    dplyr::filter(!is.na(Pitch)) %>%
    dplyr::mutate(F1_mad = (abs(F1_Hz - median(F1_Hz))/ mad(F1_Hz, constant = 1.4826)) > 2.5,
                  F2_mad = (abs(F2_Hz - median(F2_Hz))/ mad(F2_Hz, constant = 1.4826)) > 2.5) %>%
    dplyr::filter(F1_mad == FALSE & F2_mad == FALSE) %>%
    dplyr::mutate(mDist = mahalanobis(cbind(.$F1_Hz, .$F2_Hz),
                                      colMeans(cbind(.$F1_Hz, .$F2_Hz)),
                                      cov = cov(cbind(.$F1_Hz, .$F2_Hz))),
                  mDist_sd = abs(scale(mDist,center = T))) %>%
    #dplyr::mutate(mDistOutlier = (stats::pchisq(mDist, df=1, lower.tail=FALSE)) < .001) %>%
    dplyr::filter(mDist_sd < 1.5)
  
  c <- 2
  while(c < NROW(Formants_PRAAT)){
    Formants_PRAAT$F1_Hz[c] <- ifelse(is.na(Formants_PRAAT$F1_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F1_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F1_Hz[c])
    Formants_PRAAT$F2_Hz[c] <- ifelse(is.na(Formants_PRAAT$F2_Hz[c-1]) &&
                                        is.na(Formants_PRAAT$F2_Hz[c+1]),
                                      NA,
                                      Formants_PRAAT$F2_Hz[c])
    c <- c + 1
  }
  rm(c)
  
    Hull_b <- cHull(Formants_PRAAT$F1_b, Formants_PRAAT$F2_b)
### Plotting Hull
      convexCoords <- Formants_PRAAT %>%
        dplyr::select(F1_b, F2_b) %>%
        as.matrix() %>%
        grDevices::chull()
      convex <- Formants_PRAAT %>%
        slice(convexCoords)

      hullPlot_1.5 <- ggplot(aes(F2_b, F1_b),
                         data = Formants_PRAAT) +
        geom_point(shape = 21) +
        geom_polygon(data = convex,
                     alpha = .5,
                     color = "#1279B5",
                     fill = NA,
                     size = 1.5) +
        annotate("text", x = text_x, y = text_y, label = paste("Hull =",round(Hull_b,2))) +
        scale_y_reverse() +
        scale_x_reverse() +
        xlim(xlims) +
        ylim(ylims) +
        theme_classic() + labs(title = paste("1.5 SD")) + xlab("F2 (Bark)") + ylab("F1 (Bark)") +
        theme(plot.title = element_text(hjust = 0.5),
              aspect.ratio = 1)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the
existing scale.
Scale for 'y' is already present. Adding another scale for 'y', which will replace the
existing scale.
      hullPlot_1.5

      
# Combined ----
      ggpubr::ggarrange(hullPlot_1.5, hullPlot_2, hullPlot_2.5, hullPlot_3,
                        ncol = 4)
      ggsave(filename = "Plots/Hull at Different Filters.png",
             height = 3,
             width= 9,
             units = "in",
             scale = 1)

NA

Listener Demographic Information


ListenerDemo <- Listeners %>%
  furniture::table1(age, gender, race, ethnicity)

ListenerDemo

Speaker Demographics


SpeakerDemo <- AcousticData %>%
  dplyr::select(c(Speaker, Sex, Etiology))

Ages <- rio::import("Prepped Data/Speaker Ages.xlsx")

SpeakerDemo <- full_join(SpeakerDemo, Ages, by = "Speaker")

SpeakerDemoInfo <- SpeakerDemo %>%
  furniture::table1(Sex, Etiology, Age, na.rm = F)

SpeakerDemoInfo

SpeakerDemo %>%
  dplyr::summarize(mean_age = mean(Age, na.rm = T), age_sd = sd(Age, na.rm = T), age_range = range(Age, na.rm = T))
LS0tCnRpdGxlOiAiVm93ZWwgQWNvdXN0aWNzIGFzIFByZWRpY3RvcnMgb2YgU3BlZWNoIEludGVsbGlnaWJpbGl0eSBpbiBEeXNhcnRocmlhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIHRoZSBjb2RlIGZvciB0aGUgc3RhdGlzdGljYWwgYW5hbHlzaXMgZm9yICJWb3dlbCBBY291c3RpY3MgYXMgUHJlZGljdG9ycyBvZiBTcGVlY2ggSW50ZWxsaWdpYmlsaXR5IGluIER5c2FydGhyaWEuIgoKIyBMb2FkaW5nIFBhY2thZ2VzCgpgYGB7cn0KCmxpYnJhcnkocmlvKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShpcnIpICMgaW5zdGFsbC5wYWNrYWdlcygnaXJyJykKbGlicmFyeShwZXJmb3JtYW5jZSkKbGlicmFyeShjYXIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KCJIbWlzYyIpICMgaW5zdGFsbC5wYWNrYWdlcygnSG1pc2MnKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KGZ1cm5pdHVyZSkgIyBpbnN0YWxsLnBhY2thZ2VzKCdmdXJuaXR1cmUnKQpsaWJyYXJ5KGd0KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShrcykKbGlicmFyeShlbXVSKSAjIGluc3RhbGwucGFja2FnZXMoJ2VtdVInKQpsaWJyYXJ5KG1zbFRvb2xzKSAjIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiQXVzdGluUlRob21wc29uL21zbFRvb2xzIikKCmBgYAoKIyBVcGxvYWQgRGF0YXNldHMKCmBgYHtyfQoKUmVsaWFiaWxpdHkgPC0gcmlvOjppbXBvcnQoIlByZXBwZWQgRGF0YS9SZWxpYWJpbGl0eSBEYXRhLmNzdiIpCkFjb3VzdGljRGF0YSA8LSByaW86OmltcG9ydCgiUHJlcHBlZCBEYXRhL0Fjb3VzdGljTWVhc3VyZXMuY3N2IikgJT4lCiAgZHBseXI6Om11dGF0ZShpbnREaWZmID0gVkFTIC0gdHJhbnNBY2MpCgpBY291c3RpY0RhdGEgPC0gQWNvdXN0aWNEYXRhICU+JQogIGRwbHlyOjpmaWx0ZXIoIWdyZXBsKCJfcmVsIiwgU3BlYWtlcikpICU+JQogIGRwbHlyOjpzZWxlY3QoYyhTcGVha2VyLCBTZXgsIEV0aW9sb2d5LCB2b3dlbF9FRF9iLCBWU0FfYiwKICAgICAgICAgICAgICAgICAgSHVsbF9iLEh1bGxfYlZTRF8yNSwgSHVsbF9iVlNEXzUwLCBIdWxsX2JWU0RfNzUsCiAgICAgICAgICAgICAgICAgIFZBUywgdHJhbnNBY2MpKSAlPiUKICBkcGx5cjo6bXV0YXRlKEV0aW9sb2d5ID0gYXMuZmFjdG9yKEV0aW9sb2d5KSwKICAgICAgICAgICAgICAgIFNleCA9IGFzLmZhY3RvcihTZXgpLAogICAgICAgICAgICAgICAgU3BlYWtlciA9IGFzLmZhY3RvcihTcGVha2VyKSkKCkxpc3RlbmVycyA8LSByaW86OmltcG9ydCgiUHJlcHBlZCBEYXRhL0xpc3RlbmVyX0RlbW9ncmFwaGljcy5jc3YiKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFjKFN0YXJ0RGF0ZTpwcm9sb2ZpY0lELCBRMi40XzZfVEVYVCwgUTMuMl84X1RFWFQsIEF1ZGlvQ2hlY2s6RVAzKSkKCkxpc3RlbmVycyRyYWNlW0xpc3RlbmVycyRRMy4zXzdfVEVYVCA9PSAiTmF0aXZlIEFtZXJpY2FuLyBBZnJpY2FuIGFtZXJjaW5nIl0gPC0gIkJpcmFjaWFsIG9yIE11bHRpcmFjaWFsIgpgYGAKCgojIEludGVyLXJhdGVyIFJlbGlhYmlsaXR5CgpUd28gcmF0ZXJzICh0aGUgZmlyc3QgdHdvIGF1dGhvcnMpIGNvbXBsZXRlZCB2b3dlbCBzZWdtZW50YXRpb24gZm9yIHRoZSBzcGVha2Vycy4gVG8gY2FsY3VsYXRlIGludGVyLXJhdGVyIHJlbGlhYmlsaXR5LCAyMCUgb2YgdGhlIHNwZWFrZXJzIHdlcmUgc2VnbWVudGVkIGFnYWluIGJ5IHRoZSBvdGhlciByYXRlci4gVHdvLXdheSBpbnRyYWNsYXNzIGNvZWZmaWNpZW50cyB3ZXJlIGNvbXB1dGVkIGZvciB0aGUgZXh0cmFjdGVkIEYxIGFuZCBGMiBmcm9tIHRoZSB0ZW1wb3JhbCBtaWRwb2ludCBvZiB0aGUgdm93ZWwgc2VnbWVudHMuIFNpbmNlIG9ubHkgb25lIHNldCBvZiByYXRpbmdzIHdpbGwgYmUgdXNlZCBpbiB0aGUgZGF0YSBhbmFseXNpcywgd2UgZm9jdXMgb24gdGhlIHNpbmdsZSBJQ0MgcmVzdWx0cyBhbmQgaW50ZXJwcmV0YXRpb24uIEhvd2V2ZXIsIHdlIGFsc28gcmVwb3J0IHRoZSBhdmVyYWdlIElDQyB2YWx1ZXMgdG8gYmUgY29tcHJlaGVuc2l2ZS4KCmBgYHtyfQoKIyMgQ3JlYXRpbmcgbmV3IGRhdGEgZnJhbWVzIHRvIGNhbGN1bGF0ZSBJQ0MgZm9yIGV4dHJhY3RlZCBGMSBhbmQgRjIgdmFsdWVzCgpGMV9SZWwgPC0gUmVsaWFiaWxpdHkgJT4lCiAgZHBseXI6OnNlbGVjdChjKEYxLCBGMV9yZWwpKQoKRjJfUmVsIDwtIFJlbGlhYmlsaXR5ICU+JQogIGRwbHlyOjpzZWxlY3QoYyhGMiwgRjJfcmVsKSkKICAKIyMgU2luZ2xlIElDQyBmb3IgRjEKU2luZ2xlX0YxIDwtIGlycjo6aWNjKEYxX1JlbCwgbW9kZWwgPSAidHdvd2F5IiwgdHlwZSA9ICJhZ3JlZW1lbnQiLCB1bml0ID0gInNpbmdsZSIpCgojIyBBdmVyYWdlIElDQyBmb3IgRjEKQXZlcmFnZV9GMSA8LSBpcnI6OmljYyhGMV9SZWwsIG1vZGVsID0gInR3b3dheSIsIHR5cGUgPSAiYWdyZWVtZW50IiwgdW5pdCA9ICJhdmVyYWdlIikKCiMjIFNpbmdsZSBJQ0MgZm9yIEYyClNpbmdsZV9GMiA8LSBpcnI6OmljYyhGMl9SZWwsIG1vZGVsID0gInR3b3dheSIsIHR5cGUgPSAiYWdyZWVtZW50IiwgdW5pdCA9ICJzaW5nbGUiKQoKIyMgQXZlcmFnZSBJQ0MgZm9yIEYyCkF2ZXJhZ2VfRjIgPC0gaXJyOjppY2MoRjJfUmVsLCBtb2RlbCA9ICJ0d293YXkiLCB0eXBlID0gImFncmVlbWVudCIsIHVuaXQgPSAiYXZlcmFnZSIpCgojIyBJbnRlci1yYXRlciByZWxpYWJpbGl0eSByZXN1bHRzIGFuZCBpbnRlcnByZXRhdGlvbgoKcHJpbnQocGFzdGUoIlNpbmdsZSBJQ0MgZm9yIEYxIGlzICIsIHJvdW5kKFNpbmdsZV9GMSR2YWx1ZSwgZGlnaXRzID0gMyksICIuICIsIAogICAgICAgICAgICAiVGhlIDk1JSBDSSBpcyBbIiwgcm91bmQoU2luZ2xlX0YxJGxib3VuZCwgZGlnaXRzID0gMyksICIgLSAiLCByb3VuZChTaW5nbGVfRjEkdWJvdW5kLCBkaWdpdHMgPSAzKSwgIl0uIiwgc2VwID0gIiIpKQoKcHJpbnQocGFzdGUoIlNpbmdsZSBJQ0MgZm9yIEYyIGlzICIsIHJvdW5kKFNpbmdsZV9GMiR2YWx1ZSwgZGlnaXRzID0gMyksICIuICIsIAogICAgICAgICAgICAiVGhlIDk1JSBDSSBpcyBbIiwgcm91bmQoU2luZ2xlX0YyJGxib3VuZCwgZGlnaXRzID0gMyksICIgLSAiLCByb3VuZChTaW5nbGVfRjIkdWJvdW5kLCBkaWdpdHMgPSAzKSwgIl0uIiwgc2VwID0gIiIpKQoKcHJpbnQocGFzdGUoIkF2ZXJhZ2UgSUNDIGZvciBGMSBpcyAiLCByb3VuZChBdmVyYWdlX0YxJHZhbHVlLCBkaWdpdHMgPSAzKSwgIi4gIiwgCiAgICAgICAgICAgICJUaGUgOTUlIENJIGlzIFsiLCByb3VuZChBdmVyYWdlX0YxJGxib3VuZCwgZGlnaXRzID0gMyksICIgLSAiLCByb3VuZChBdmVyYWdlX0YxJHVib3VuZCwgZGlnaXRzID0gMyksICJdLiIsIHNlcCA9ICIiKSkKCnByaW50KHBhc3RlKCJBdmVyYWdlIElDQyBmb3IgRjIgaXMgIiwgcm91bmQoQXZlcmFnZV9GMiR2YWx1ZSwgZGlnaXRzID0gMyksICIuICIsIAogICAgICAgICAgICAiVGhlIDk1JSBDSSBpcyBbIiwgcm91bmQoQXZlcmFnZV9GMiRsYm91bmQsIGRpZ2l0cyA9IDMpLCAiIC0gIiwgcm91bmQoQXZlcmFnZV9GMiR1Ym91bmQsIGRpZ2l0cyA9IDMpLCAiXS4iLCBzZXAgPSAiIikpCgpwcmludCgiVGh1cywgaW50ZXJyYXRlciByZWxpYWJpbGl0eSBmb3IgdGhlIGV4dHJhY3RlZCBGMSBhbmQgRjIgdmFsdWVzIGZyb20gdGhlIHZvd2VsIHNlZ21lbnRzIHdhcyBnb29kIHRvIGV4Y2VsbGVudC4iKQoKIyMgUmVtb3ZpbmcgZXh0cmEgZGF0YSBmcmFtZXMgZnJvbSBlbnZpcm9ubWVudAoKcm0oRjFfUmVsLCBGMl9SZWwsIFJlbGlhYmlsaXR5LCBTaW5nbGVfRjEsIFNpbmdsZV9GMiwgQXZlcmFnZV9GMSwgQXZlcmFnZV9GMikKCmBgYAoKCiMgRGVzY3JpcHRpdmUgU3RhdGlzdGljcwoKIyMgQ29ycmVsYXRpb25zCgpgYGB7cn0KQ29yck1hdHJpeCA8LSBBY291c3RpY0RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChWU0FfYiwgdm93ZWxfRURfYiwgSHVsbF9iLCBIdWxsX2JWU0RfMjUsIEh1bGxfYlZTRF83NSwgVkFTLCB0cmFuc0FjYykgJT4lCiAgYXMubWF0cml4KCkgJT4lCiAgSG1pc2M6OnJjb3JyKCkKCkNvcnJNYXRyaXhQIDwtIENvcnJNYXRyaXgkUCA8IC4wNQoKQ29yck1hdHJpeCA8LSBDb3JyTWF0cml4JHIKCnN0YXRzOjpjb3IudGVzdChBY291c3RpY0RhdGEkVlNBX2IsIEFjb3VzdGljRGF0YSR2b3dlbF9FRF9iLCBtZXRob2QgPSAicGVhcnNvbiIpCnN0YXRzOjpjb3IudGVzdChBY291c3RpY0RhdGEkSHVsbF9iLCBBY291c3RpY0RhdGEkSHVsbF9iVlNEXzI1LCBtZXRob2QgPSAicGVhcnNvbiIpCgoKd3JpdGUuY3N2KENvcnJNYXRyaXgsIGZpbGUgPSAiVGFibGVzL0NvcnJlbGF0aW9uIE1hdHJpeC5jc3YiKQpybShDb3JyTWF0cml4KQoKYGBgCgojIFJlc2VhcmNoIFExOiBNb2RlbGluZyBJbnRlbGxpZ2liaWxpdHkKCiMjIE9ydGhvZ3JhcGhpYyBUcmFuc2NyaXB0aW9ucwojIyMgTW9kZWwgMQpgYGB7cn0KCiMgU3BlY2lmeWluZyBNb2RlbCAxCgpPVF9Nb2RlbDEgPC0gbG0odHJhbnNBY2MgfiBIdWxsX2JWU0RfMjUsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAxIEFzc3VtcHRpb25zIAoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX01vZGVsMSkKCiMjIE1vZGVsIDEgU3VtbWFyeQoKc3VtbWFyeShPVF9Nb2RlbDEpCgpgYGAKCiMjIyBNb2RlbCAyCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCAyCgpPVF9Nb2RlbDIgPC0gbG0odHJhbnNBY2MgfiBIdWxsX2JWU0RfMjUgKyBIdWxsX2JWU0RfNzUsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAyIEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChPVF9Nb2RlbDIpCgojIyBNb2RlbCAyIFN1bW1hcnkKCnN1bW1hcnkoT1RfTW9kZWwyKQoKIyMgTW9kZWwgMSBhbmQgTW9kZWwgMiBDb21wYXJpc29uCgphbm92YShPVF9Nb2RlbDEsIE9UX01vZGVsMikKCmBgYAoKIyMjIE1vZGVsIDNhCmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCAzCgpPVF9Nb2RlbDNhIDwtIGxtKHRyYW5zQWNjIH4gSHVsbF9iVlNEXzI1ICsgSHVsbF9iVlNEXzc1ICsgSHVsbF9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgTW9kZWwgMyBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoT1RfTW9kZWwzYSkKcGVyZm9ybWFuY2U6OmNoZWNrX2NvbGxpbmVhcml0eShPVF9Nb2RlbDNhKQoKCiMjIE1vZGVsIDMgU3VtbWFyeQoKc3VtbWFyeShPVF9Nb2RlbDNhKQoKIyMgTW9kZWwgMiBhbmQgTW9kZWwgMyBDb21wYXJpc29uCgphbm92YShPVF9Nb2RlbDIsIE9UX01vZGVsM2EpCgpgYGAKCiMjIyBNb2RlbCAzYgpgYGB7cn0KCiMjIFNwZWNpZnlpbmcgTW9kZWwgMwoKT1RfTW9kZWwzYiA8LSBsbSh0cmFuc0FjYyB+IEh1bGxfYlZTRF83NSArIEh1bGxfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDMgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX01vZGVsM2IpCnBlcmZvcm1hbmNlOjpjaGVja19jb2xsaW5lYXJpdHkoT1RfTW9kZWwzYikKCgojIyBNb2RlbCAzIFN1bW1hcnkKCnN1bW1hcnkoT1RfTW9kZWwzYikKCmBgYAoKIyMjIE1vZGVsIDQKYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDQKCk9UX01vZGVsNCA8LSBsbSh0cmFuc0FjYyB+IEh1bGxfYlZTRF83NSArIEh1bGxfYiArIFZTQV9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgTW9kZWwgNCBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoT1RfTW9kZWw0KQpwZXJmb3JtYW5jZTo6Y2hlY2tfY29sbGluZWFyaXR5KE9UX01vZGVsNCkKCiMjIE1vZGVsIDQgU3VtbWFyeQoKc3VtbWFyeShPVF9Nb2RlbDQpCgojIyBNb2RlbCAzIGFuZCBNb2RlbCA0IENvbXBhcmlzb24KCmFub3ZhKE9UX01vZGVsM2IsIE9UX01vZGVsNCkKCmBgYAoKIyMjIE1vZGVsIDUKYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDUKCk9UX01vZGVsNSA8LSBsbSh0cmFuc0FjYyB+IEh1bGxfYlZTRF83NSArIFZTQV9iICsgdm93ZWxfRURfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDQgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX01vZGVsNSkKcGVyZm9ybWFuY2U6OmNoZWNrX2NvbGxpbmVhcml0eShPVF9Nb2RlbDUpCgojIyBNb2RlbCA0IFN1bW1hcnkKCnN1bW1hcnkoT1RfTW9kZWw1KQoKIyMgTW9kZWwgMyBhbmQgTW9kZWwgNCBDb21wYXJpc29uCgphbm92YShPVF9Nb2RlbDQsIE9UX01vZGVsNSkKCmBgYAoKCiMjIyBGaW5hbCBNb2RlbAoKYGBge3J9CgojIyBTcGVjaWZ5aW5nIEZpbmFsIE1vZGVsCgpPVF9Nb2RlbF9maW5hbCA8LSBsbSh0cmFuc0FjYyB+IFZTQV9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgRmluYWwgTW9kZWwgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKE9UX01vZGVsX2ZpbmFsKQoKIyMgRmluYWwgTW9kZWwgU3VtbWFyeQoKc3VtbWFyeShPVF9Nb2RlbF9maW5hbCkKY29uZmludChPVF9Nb2RlbF9maW5hbCkKCmBgYAoKIyMgVkFTIE1vZGVscwoKIyMjIE1vZGVsIDEKYGBge3J9CgojIFNwZWNpZnlpbmcgTW9kZWwgMQoKVkFTX01vZGVsMSA8LSBsbShWQVMgfiBIdWxsX2JWU0RfMjUsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCAxIEFzc3VtcHRpb25zIAoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKFZBU19Nb2RlbDEpCgojIyBNb2RlbCAxIFN1bW1hcnkKCnN1bW1hcnkoVkFTX01vZGVsMSkKCmBgYAoKIyMjIE1vZGVsIDIKYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDIKClZBU19Nb2RlbDIgPC0gbG0oVkFTIH4gSHVsbF9iVlNEXzI1ICsgSHVsbF9iVlNEXzc1LCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgTW9kZWwgMiBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoVkFTX01vZGVsMikKCiMjIE1vZGVsIDIgU3VtbWFyeQoKc3VtbWFyeShWQVNfTW9kZWwyKQoKIyMgTW9kZWwgMSBhbmQgTW9kZWwgMiBDb21wYXJpc29uCgphbm92YShWQVNfTW9kZWwxLCBWQVNfTW9kZWwyKQoKYGBgCgojIyMgTW9kZWwgM2EKYGBge3J9CgojIyBTcGVjaWZ5aW5nIE1vZGVsIDMKClZBU19Nb2RlbDNhIDwtIGxtKFZBUyB+IEh1bGxfYlZTRF8yNSArIEh1bGxfYlZTRF83NSArIEh1bGxfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDMgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKFZBU19Nb2RlbDNhKQpwZXJmb3JtYW5jZTo6Y2hlY2tfY29sbGluZWFyaXR5KFZBU19Nb2RlbDNhKQoKIyMgTW9kZWwgMyBTdW1tYXJ5CgpzdW1tYXJ5KFZBU19Nb2RlbDNhKQoKIyMgTW9kZWwgMiBhbmQgTW9kZWwgMyBDb21wYXJpc29uCgphbm92YShWQVNfTW9kZWwyLCBWQVNfTW9kZWwzYSkKCmBgYAoKIyMjIE1vZGVsIDNiClRoaXMgbW9kZWwgcmVtb3ZlcyBWU0QyNSBiZWNhdXNlIG9mIGl0J3MgaGlnaCBWSUYgdmFsdWUgPiA1LgpgYGB7cn0KCiMjIFNwZWNpZnlpbmcgTW9kZWwgM2IKClZBU19Nb2RlbDNiIDwtIGxtKFZBUyB+IEh1bGxfYlZTRF83NSArIEh1bGxfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKCiMjIE1vZGVsIDMgQXNzdW1wdGlvbiBDaGVjawoKcGVyZm9ybWFuY2U6OmNoZWNrX21vZGVsKFZBU19Nb2RlbDNiKQpwZXJmb3JtYW5jZTo6Y2hlY2tfY29sbGluZWFyaXR5KFZBU19Nb2RlbDNiKQoKIyMgTW9kZWwgMyBTdW1tYXJ5CgpzdW1tYXJ5KFZBU19Nb2RlbDNiKQoKYGBgCiMjIyBNb2RlbCA0CmBgYHtyfQoKIyMgU3BlY2lmeWluZyBNb2RlbCA0CgpWQVNfTW9kZWw0IDwtIGxtKFZBUyB+IEh1bGxfYlZTRF83NSArIEh1bGxfYiArIFZTQV9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyMgTW9kZWwgNCBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoVkFTX01vZGVsNCkKcGVyZm9ybWFuY2U6OmNoZWNrX2NvbGxpbmVhcml0eShWQVNfTW9kZWw0KQoKIyMgTW9kZWwgNCBTdW1tYXJ5CgpzdW1tYXJ5KFZBU19Nb2RlbDQpCgojIyBNb2RlbCAzIGFuZCBNb2RlbCA0IENvbXBhcmlzb24KCmFub3ZhKFZBU19Nb2RlbDNiLCBWQVNfTW9kZWw0KQoKYGBgCgojIyMgTW9kZWwgNQpgYGB7cn0KCiMjIFNwZWNpZnlpbmcgTW9kZWwgNQoKVkFTX01vZGVsNSA8LSBsbShWQVMgfiBIdWxsX2JWU0RfNzUgKyBIdWxsX2IgKyBWU0FfYiArIHZvd2VsX0VEX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBNb2RlbCA1IEFzc3VtcHRpb24gQ2hlY2sKCnBlcmZvcm1hbmNlOjpjaGVja19tb2RlbChWQVNfTW9kZWw1KQoKIyMgTW9kZWwgNSBTdW1tYXJ5CgpzdW1tYXJ5KFZBU19Nb2RlbDUpCgojIyBNb2RlbCA0IGFuZCBNb2RlbCA1IENvbXBhcmlzb24KCmFub3ZhKFZBU19Nb2RlbDQsIFZBU19Nb2RlbDUpCgpgYGAKCiMjIyBGaW5hbCBNb2RlbAoKYGBge3J9CgojIyBTcGVjaWZ5aW5nIEZpbmFsIE1vZGVsCgpWQVNfTW9kZWxfZmluYWwgPC0gbG0oVkFTIH4gVlNBX2IsIGRhdGEgPSBBY291c3RpY0RhdGEpCgojIyBGaW5hbCBNb2RlbCBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoVkFTX01vZGVsX2ZpbmFsKQoKIyMgRmluYWwgTW9kZWwgU3VtbWFyeQoKc3VtbWFyeShWQVNfTW9kZWxfZmluYWwpCmNvbmZpbnQoVkFTX01vZGVsX2ZpbmFsKQoKYGBgCgojIFJlc2VhcmNoIFEyOiBSZWxhdGlvbnNoaXAgYmV0d2VlbiBPVCBhbmQgVkFTCgpNb2RlbCAxCmBgYHtyfQoKIyBTcGVjaWZ5IE1vZGVsCgpPVF9WQVNfbW9kZWwgPC0gbG0odHJhbnNBY2MgfiBWQVMqRXRpb2xvZ3kgKyBWQVMqU2V4LCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKIyBBc3N1bXB0aW9uIENoZWNrCgpwZXJmb3JtYW5jZTo6Y2hlY2tfbW9kZWwoT1RfVkFTX21vZGVsKQoKIyBNb2RlbCBSZXN1bHRzCgpzdW1tYXJ5KE9UX1ZBU19tb2RlbCkKCmBgYAoKIyMgRmluYWwgTGluZWFyIE1vZGVsCgpgYGB7cn0KCiMgU3BlY2lmeSBGaW5hbCBNb2RlbAoKT1RfVkFTX2ZpbmFsIDwtIGxtKHRyYW5zQWNjIH4gVkFTLCBkYXRhID0gQWNvdXN0aWNEYXRhKQoKY29uZmludChPVF9WQVNfZmluYWwpCgojIE1vZGVsIFJlc3VsdHMKCnN1bW1hcnkoT1RfVkFTX2ZpbmFsKQoKYGBgCgojIENvcm5lciBEaXNwZXJzaW9uCkxvb2tpbmcgYXQgY29ybmVyIGRpc3BlcnNpb24gYXMgdGhlIHNvbGUgcHJlZGljdG9yLgoKYGBge3J9CgojIFNwZWNpZnkgRmluYWwgTW9kZWwKCk9UX2Nvcm5EaXNwIDwtIGxtKHRyYW5zQWNjIH4gdm93ZWxfRURfYiwgZGF0YSA9IEFjb3VzdGljRGF0YSkKc3VtbWFyeShPVF9jb3JuRGlzcCkKClZBU19jb3JuRGlzcCA8LSBsbShWQVMgfiB2b3dlbF9FRF9iLCBkYXRhID0gQWNvdXN0aWNEYXRhKQpzdW1tYXJ5KFZBU19jb3JuRGlzcCkKCmBgYAojIE1hbnVzY3JpcHQgVGFibGVzCiMjIERlc2NyaXB0aXZlcyBUYWJsZQpgYGB7cn0KZ3REYXRhIDwtIEFjb3VzdGljRGF0YSAlPiUKICByYmluZCguLEFjb3VzdGljRGF0YSAlPiUKICAgICAgICAgIGRwbHlyOjptdXRhdGUoRXRpb2xvZ3kgPSAiQWxsIEV0aW9sb2dpZXMiKSkgJT4lCiAgcmJpbmQoLixBY291c3RpY0RhdGEgJT4lCiAgICAgICAgICByYmluZCguLEFjb3VzdGljRGF0YSAlPiUKICAgICAgICAgIGRwbHlyOjptdXRhdGUoRXRpb2xvZ3kgPSAiQWxsIEV0aW9sb2dpZXMiKSkgJT4lCiAgICAgICAgICBkcGx5cjo6bXV0YXRlKFNleCA9ICJBbGwiKSkgJT4lCiAgZHBseXI6Om11dGF0ZShTZXggPSBhcy5mYWN0b3IoU2V4KSwKICAgICAgICAgICAgICAgIEV0aW9sb2d5ID0gYXMuZmFjdG9yKEV0aW9sb2d5KSkgJT4lCiAgZHBseXI6Omdyb3VwX2J5KFNleCwgRXRpb2xvZ3kpICU+JQogIGRwbHlyOjpzdW1tYXJpemUoVlNBX21lYW4gPSBtZWFuKFZTQV9iLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWU0Ffc2QgPSBzZChWU0FfYiwgbmEucm0gPSBUKSwKICAgICAgICAgICAgICAgICAgIERpc3BfbWVhbiA9IG1lYW4odm93ZWxfRURfYiwgbmEucm0gPVQpLAogICAgICAgICAgICAgICAgICAgRGlzcF9zZCA9IHNkKHZvd2VsX0VEX2IsIG5hLnJtID1UKSwKICAgICAgICAgICAgICAgICAgIEh1bGxfbWVhbiA9IG1lYW4oSHVsbF9iLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBIdWxsX3NkID0gc2QoSHVsbF9iLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWU0QyNV9tZWFuID0gbWVhbihIdWxsX2JWU0RfMjUsIG5hLnJtID1UKSwKICAgICAgICAgICAgICAgICAgIFZTRDI1X3NkID0gc2QoSHVsbF9iVlNEXzI1LCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWU0Q1MF9tZWFuID0gbWVhbihIdWxsX2JWU0RfNTAsIG5hLnJtID1UKSwKICAgICAgICAgICAgICAgICAgIFZTRDUwX3NkID0gc2QoSHVsbF9iVlNEXzUwLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWU0Q3NV9tZWFuID0gbWVhbihIdWxsX2JWU0RfNzUsIG5hLnJtID1UKSwKICAgICAgICAgICAgICAgICAgIFZTRDc1X3NkID0gc2QoSHVsbF9iVlNEXzc1LCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWQVNfbWVhbiA9IG1lYW4oVkFTLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBWQVNfc2QgPSBzZChWQVMsIG5hLnJtID1UKSwKICAgICAgICAgICAgICAgICAgIE9UX21lYW4gPSBtZWFuKHRyYW5zQWNjLCBuYS5ybSA9VCksCiAgICAgICAgICAgICAgICAgICBPVF9zZCA9IHNkKHRyYW5zQWNjLCBuYS5ybSA9VCkpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gVlNBX21lYW46T1Rfc2QsIG5hbWVzX3RvID0gIk1lYXN1cmUiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiVmFsdWUiKSAlPiUKICBkcGx5cjo6bXV0YXRlKFZhbHVlID0gcm91bmQoVmFsdWUsIGRpZ2l0cyA9IDIpLAogICAgICAgICAgICAgICAgbWVhblNEID0gaWZlbHNlKGdyZXBsKCJfbWVhbiIsTWVhc3VyZSksIk0iLCJzZCIpLAogICAgICAgICAgICAgICAgTWVhc3VyZSA9IGdzdWIoIl9tZWFuIiwiIixNZWFzdXJlKSwKICAgICAgICAgICAgICAgIE1lYXN1cmUgPSBnc3ViKCJfc2QiLCIiLE1lYXN1cmUpLAogICAgICAgICAgICAgICAgRXRpb2xvZ3kgPSBwYXN0ZShFdGlvbG9neSxtZWFuU0QsIHNlcCA9ICJfIiksCiAgICAgICAgICAgICAgICBTZXggPSBjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgIFNleCA9PSAiQWxsIiB+ICJBbGwgU3BlYWtlcnMiLAogICAgICAgICAgICAgICAgICBTZXggPT0gIk0iIH4gIk1hbGUgU3BlYWtlcnMiLAogICAgICAgICAgICAgICAgICBTZXggPT0gIkYiIH4gIkZlbWFsZSBTcGVha2VycyIKICAgICAgICAgICAgICAgICkpICU+JQogIGRwbHlyOjpzZWxlY3QoIW1lYW5TRCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IEV0aW9sb2d5LCB2YWx1ZXNfZnJvbSA9ICJWYWx1ZSIpICU+JQogIGRwbHlyOjpmaWx0ZXIoTWVhc3VyZSAhPSAiVlNENTAiKQoKZ3REYXRhICU+JQogIGd0OjpndCgKICAgIHJvd25hbWVfY29sID0gIk1lYXN1cmUiLAogICAgZ3JvdXBuYW1lX2NvbCA9ICJTZXgiLAogICkgJT4lCiAgZm10X251bWJlcigKICAgIGNvbHVtbnMgPSAnQWxsIEV0aW9sb2dpZXNfTSc6UERfc2QsCiAgICBkZWNpbWFscyA9IDIKICApICU+JQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSAiQWxsIEV0aW9sb2dpZXMiLAogICAgY29sdW1ucyA9IGMoJ0FsbCBFdGlvbG9naWVzX00nLCAnQWxsIEV0aW9sb2dpZXNfc2QnKQogICkgJT4lCiAgICB0YWJfc3Bhbm5lcigKICAgIGxhYmVsID0gIkFMUyIsCiAgICBjb2x1bW5zID0gYyhBTFNfTSwgQUxTX3NkKQogICkgJT4lCiAgdGFiX3NwYW5uZXIoCiAgICBsYWJlbCA9ICJQRCIsCiAgICBjb2x1bW5zID0gYyhQRF9NLCBQRF9zZCkKICApICU+JQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSAiSEQiLAogICAgY29sdW1ucyA9IGMoSERfTSwgSERfc2QpCiAgKSAlPiUKICB0YWJfc3Bhbm5lcigKICAgIGxhYmVsID0gIkF0YXhpYyIsCiAgICBjb2x1bW5zID0gYyhBdGF4aWNfTSwgQXRheGljX3NkKQogICkgJT4lCiAgZ3Q6OmNvbHNfbW92ZV90b19zdGFydCgKICAgIGNvbHVtbnMgPSBjKCdBbGwgRXRpb2xvZ2llc19NJywnQWxsIEV0aW9sb2dpZXNfc2QnKQogICkgJT4lCiAgcm93X2dyb3VwX29yZGVyKAogICAgZ3JvdXBzID0gYygiQWxsIFNwZWFrZXJzIiwgIkZlbWFsZSBTcGVha2VycyIsICJNYWxlIFNwZWFrZXJzIikKICAgICkgJT4lCiAgY29sc19sYWJlbCgKICAgICAnQWxsIEV0aW9sb2dpZXNfTScgPSAiTSIsCiAgICAgJ0FsbCBFdGlvbG9naWVzX3NkJyA9ICJTRCIsCiAgICAgQUxTX00gPSAiTSIsCiAgICAgQUxTX3NkID0gIlNEIiwKICAgICBQRF9NID0gIk0iLAogICAgIFBEX3NkID0gIlNEIiwKICAgICBIRF9NID0gIk0iLAogICAgIEhEX3NkID0gIlNEIiwKICAgICBBdGF4aWNfTSA9ICJNIiwKICAgICBBdGF4aWNfc2QgPSAiU0QiCiAgKSAlPiUKICBndHNhdmUoIkRlc2NyaXB0aXZlc1RhYmxlLmh0bWwiLCBwYXRoID0gIlRhYmxlcyIpCgpgYGAKCiMjIE9UIE1vZGVsCmBgYHtyfQpzalBsb3Q6OnRhYl9tb2RlbChPVF9Nb2RlbDEsCiAgICAgICAgICAgICAgICAgIE9UX01vZGVsMiwKICAgICAgICAgICAgICAgICAgT1RfTW9kZWwzYiwKICAgICAgICAgICAgICAgICAgT1RfTW9kZWw0LAogICAgICAgICAgICAgICAgICBPVF9Nb2RlbDUsCiAgICAgICAgICAgICAgICAgIE9UX01vZGVsX2ZpbmFsLAogICAgICAgICAgICAgICAgICBzaG93LmNpID0gRiwKICAgICAgICAgICAgICAgICAgcC5zdHlsZSA9ICJzdGFycyIsCiAgICAgICAgICAgICAgICAgIGZpbGUgPSAiVGFibGVzL09UIE1vZGVscy5odG1sIikKYGBgCgojIyBWQVMgTW9kZWwKYGBge3J9CnNqUGxvdDo6dGFiX21vZGVsKFZBU19Nb2RlbDEsCiAgICAgICAgICAgICAgICAgIFZBU19Nb2RlbDIsCiAgICAgICAgICAgICAgICAgIFZBU19Nb2RlbDMsCiAgICAgICAgICAgICAgICAgIFZBU19Nb2RlbDQsCiAgICAgICAgICAgICAgICAgIFZBU19Nb2RlbDUsCiAgICAgICAgICAgICAgICAgIFZBU19Nb2RlbF9maW5hbCwKICAgICAgICAgICAgICAgICAgc2hvdy5jaSA9IEYsCiAgICAgICAgICAgICAgICAgIHAuc3R5bGUgPSAic3RhcnMiLAogICAgICAgICAgICAgICAgICBmaWxlID0gIlRhYmxlcy9WQVMgTW9kZWxzLmh0bWwiKQpgYGAKCiMjIE9UIHZzLiBWQVMKYGBge3J9CnNqUGxvdDo6dGFiX21vZGVsKE9UX1ZBU19tb2RlbCxPVF9WQVNfZmluYWwsCiAgICAgICAgICAgICAgICAgIHNob3cuY2kgPSBGLAogICAgICAgICAgICAgICAgICBzaG93LnJlZmx2bCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIHAuc3R5bGUgPSAic3RhcnMiLAogICAgICAgICAgICAgICAgICBmaWxlID0gIlRhYmxlcy9PVCBhbmQgVkFTIENvbXBhcmlzb24uaHRtbCIpCmBgYAoKIyBNYW51c2NyaXB0IEZpZ3VyZXMKIyMgRXhhbXBsZSBNZWFzdXJlcwpgYGB7cn0KZm9ybWFudENvbG9yIDwtICJncmV5Igpmb3JtYW50QWxwaGEgPC0gLjk1CmxpbmVDb2xvciA8LSAid2hpdGUiCmxpbmVBbHBoYSA8LSAuOAoKdm93ZWxEYXRhIDwtIHJpbzo6aW1wb3J0KCJQcmVwcGVkIERhdGEvVm93ZWwgRGF0YS5jc3YiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKFNwZWFrZXIgPT0gIkFGOCIpCgogIFBpdGNoX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLlBpdGNoIiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBGKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoUGl0Y2ggPSBWMSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBpdGNoID0gZ3N1YigiLS11bmRlZmluZWQtLSIsTkEsUGl0Y2gpLAogICAgICAgICAgICAgICAgICBQaXRjaCA9IGFzLm51bWVyaWMoUGl0Y2gpKQogIAogIEZvcm1hbnRzX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiX0Zvcm1hbnQiLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IFQpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhuZm9ybWFudHMsIEIxLkh6LiwgQjIuSHouLCBCMy5Iei4sIEY0Lkh6LiwgQjQuSHouLCBGNS5Iei4sIEI1Lkh6LikpICU+JQogICAgZHBseXI6OnJlbmFtZShUaW1lX3MgPSB0aW1lLnMuLAogICAgICAgICAgICAgICAgICBGMV9IeiA9IEYxLkh6LiwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBGMi5Iei4sCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gRjMuSHouKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBpZmVsc2UoRjFfSHogPT0gMCwgTkEsIEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBpZmVsc2UoRjJfSHogPT0gMCwgTkEsIEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBpZmVsc2UoRjNfSHogPT0gMCwgTkEsIEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gYXMubnVtZXJpYyhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gYXMubnVtZXJpYyhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKEYzX0h6KSksCiAgICAgICAgICAgICAgICAgIFRpbWVfbXMgPSBUaW1lX3MgLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9rSHogPSBGMV9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYyX2tIeiA9IEYyX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjNfa0h6ID0gRjNfSHogLyAxMDAwKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIVRpbWVfcykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVGltZV9tcywgLmJlZm9yZSA9IEYxX0h6KSAlPiUKICAgIGNiaW5kKC4sUGl0Y2hfUFJBQVQpCiAgCiAgYyA8LSAyCiAgd2hpbGUoYyA8IE5ST1coRm9ybWFudHNfUFJBQVQpKXsKICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10pCiAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdKQogICAgYyA8LSBjICsgMQogIH0KICBybShjKQogIAogIEZvcm1hbnRzX1BSQUFUIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoRjFfbWFkID09IEZBTFNFICYgRjJfbWFkID09IEZBTFNFKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG1EaXN0X3NkIDwgMikgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFjKEYxX21hZCwgRjJfbWFkLCBtRGlzdCwgbURpc3Rfc2QpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfeiA9IHNjYWxlKEYxX0h6LCBjZW50ZXIgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgRjJfeiA9IHNjYWxlKEYyX0h6LCBjZW50ZXIgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgRjNfeiA9IHNjYWxlKEYzX0h6LCBjZW50ZXIgPSBUUlVFKSwKICAgICAgICAgICAgICAgICAgRjFfYiA9IGVtdVI6OmJhcmsoRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9iID0gZW11Ujo6YmFyayhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX2IgPSBlbXVSOjpiYXJrKEYzX0h6KSkKICAKICBybShQaXRjaF9QUkFBVCkKICAKICAKIyMgQ29ybmVyIERpc3BlcnNpb24gLS0tLQogIHdlZGdlIDwtIHZvd2VsRGF0YSAlPiUKICAgIGRwbHlyOjpncm91cF9ieShWb3dlbCkgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKG1lYW5fRjEgPSBtZWFuKEYxX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjIgPSBtZWFuKEYyX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjFfeiA9IG1lYW4oRjFfel90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YyX3ogPSBtZWFuKEYyX3pfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMV9iID0gbWVhbihGMV9iX3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjJfYiA9IG1lYW4oRjJfYl90ZW1wTWlkKSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKFZvd2VsID09ICJ2IikKICAgIAogIGNvcm5lcl9kaXMgPC0gdm93ZWxEYXRhICU+JQogICAgZHBseXI6OmZpbHRlcihWb3dlbCAhPSAidiIpICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFZvd2VsKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUobWVhbl9GMSA9IG1lYW4oRjFfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMiA9IG1lYW4oRjJfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMV96ID0gbWVhbihGMV96X3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjJfeiA9IG1lYW4oRjJfel90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YxX2IgPSBtZWFuKEYxX2JfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMl9iID0gbWVhbihGMl9iX3RlbXBNaWQpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoVm93ZWxfRUQgPSBzcXJ0KChtZWFuX0YxLXdlZGdlJG1lYW5fRjEpXjIgKyAobWVhbl9GMi13ZWRnZSRtZWFuX0YyKV4yKSwKICAgICAgICAgICAgICAgICAgVm93ZWxfRURfeiA9IHNxcnQoKG1lYW5fRjFfei13ZWRnZSRtZWFuX0YxX3opXjIgKyAobWVhbl9GMl96LXdlZGdlJG1lYW5fRjJfeileMiksCiAgICAgICAgICAgICAgICAgIFZvd2VsX0VEX2IgPSBzcXJ0KChtZWFuX0YxX2Itd2VkZ2UkbWVhbl9GMV9iKV4yICsgKG1lYW5fRjJfYi13ZWRnZSRtZWFuX0YyX2IpXjIpKQoKICAgIAojIFBsb3QgQ29ybmVyIERpc3BlcnNpb24KICAgICAgIyBDaGFuZ2luZyB0byBJUEEgc3ltYm9scwogICAgICBjb3JuZXJfZGlzIDwtIGNvcm5lcl9kaXMgJT4lCiAgICAgICAgZHBseXI6Om11dGF0ZShWb3dlbCA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgICAgICBWb3dlbCA9PSAiYWUiIH4gIsOmIiwKICAgICAgICAgIFRSVUUgfiBWb3dlbAogICAgICAgICkpCiAgICAgIAogICAgICB3ZWRnZSA8LSB3ZWRnZSAlPiUKICAgICAgICBkcGx5cjo6bXV0YXRlKFZvd2VsID0gY2FzZV93aGVuKAogICAgICAgICAgVm93ZWwgPT0gInYiIH4gIsqMIiwKICAgICAgICAgIFRSVUUgfiBWb3dlbAogICAgICAgICkpCiAgICAgIAogICAgICBDRHBsb3QgPC0gZ2dwbG90KGFlcyh4PUYyX2IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RjFfYiksCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFULAogICAgICAgICAgICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UpICsgCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwKICAgICAgICAgICAgICAgICBhbHBoYSA9IGZvcm1hbnRBbHBoYSwKICAgICAgICAgICAgICAgICBjb2xvciA9IGZvcm1hbnRDb2xvcikgKyAKICAgICAgZ2VvbV9saW5lKGFlcyh4ID0gbWVhbl9GMl9iLAogICAgICAgICAgICAgICAgICAgIHkgPSBtZWFuX0YxX2IpLAogICAgICAgICAgICAgICAgZGF0YSA9IGNvcm5lcl9kaXMgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoVm93ZWw6bWVhbl9GMl9iKSAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihWb3dlbCA9PSAiaSIpICU+JQogICAgICAgICAgICAgICAgICByYmluZCguLHdlZGdlKSwKICAgICAgICAgICAgICAgIGNvbG9yID0gbGluZUNvbG9yLAogICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSwKICAgICAgICAgICAgICAgIGFscGhhID0gbGluZUFscGhhKSArCiAgICAgIGdlb21fbGluZShhZXMoeCA9IG1lYW5fRjJfYiwKICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9GMV9iKSwKICAgICAgICAgICAgICAgIGRhdGEgPSBjb3JuZXJfZGlzICU+JQogICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KFZvd2VsOm1lYW5fRjJfYikgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoVm93ZWwgPT0gImEiKSAlPiUKICAgICAgICAgICAgICAgICAgcmJpbmQoLix3ZWRnZSksCiAgICAgICAgICAgICAgICBjb2xvciA9IGxpbmVDb2xvciwKICAgICAgICAgICAgICAgIHNpemUgPSAxLjUsCiAgICAgICAgICAgICAgICBhbHBoYSA9IGxpbmVBbHBoYSkgKwogICAgICBnZW9tX2xpbmUoYWVzKHggPSBtZWFuX0YyX2IsCiAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fRjFfYiksCiAgICAgICAgICAgICAgICBkYXRhID0gY29ybmVyX2RpcyAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChWb3dlbDptZWFuX0YyX2IpICU+JQogICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKFZvd2VsID09ICLDpiIpICU+JQogICAgICAgICAgICAgICAgICByYmluZCguLHdlZGdlKSwKICAgICAgICAgICAgICAgIGNvbG9yID0gbGluZUNvbG9yLAogICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSwKICAgICAgICAgICAgICAgIGFscGhhID0gbGluZUFscGhhKSArCiAgICAgIGdlb21fbGluZShhZXMoeCA9IG1lYW5fRjJfYiwKICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9GMV9iKSwKICAgICAgICAgICAgICAgIGRhdGEgPSBjb3JuZXJfZGlzICU+JQogICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KFZvd2VsOm1lYW5fRjJfYikgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoVm93ZWwgPT0gInUiKSAlPiUKICAgICAgICAgICAgICAgICAgcmJpbmQoLix3ZWRnZSksCiAgICAgICAgICAgICAgICBjb2xvciA9IGxpbmVDb2xvciwKICAgICAgICAgICAgICAgIHNpemUgPSAxLjUsCiAgICAgICAgICAgICAgICBhbHBoYSA9IGxpbmVBbHBoYSkgKwogICAgICBnZW9tX3BvaW50KGFlcyh4ID0gbWVhbl9GMl9iLAogICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9GMV9iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFZvd2VsKSwKICAgICAgICAgICAgICAgICBkYXRhID0gY29ybmVyX2RpcyAlPiUKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChWb3dlbDptZWFuX0YyX2IpICU+JQogICAgICAgICAgICAgICAgICByYmluZCguLHdlZGdlKSwKICAgICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIkNvcm5lciBEaXNwZXJzaW9uIikpICsgeGxhYigiRjIgKEJhcmspIikgKyB5bGFiKCJGMSAoQmFyaykiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKSArCiAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYSIgPSAiIzFBQUQ3NyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiw6YiID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImkiID0gIiNGRkJGMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInUiID0gIiNGRDc4NTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIsqMIiA9ICIjQkYzMTc4IikpCiAgICBDRHBsb3QKICAgIAogICAgICBybShjb3JuZXJfZGlzLCB3ZWRnZSkKICAgICAgCiMjIFZvd2VsIFNwYWNlIEFyZWEgLS0tLQogIFZTQV9jb29yZHMgPC0gdm93ZWxEYXRhICU+JQogICAgZHBseXI6OmZpbHRlcihWb3dlbCAhPSAidiIpICU+JQogICAgZHBseXI6Omdyb3VwX2J5KFZvd2VsKSAlPiUKICAgIGRwbHlyOjpzdW1tYXJpemUobWVhbl9GMSA9IG1lYW4oRjFfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMiA9IG1lYW4oRjJfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMV96ID0gbWVhbihGMV96X3RlbXBNaWQpLAogICAgICAgICAgICAgIG1lYW5fRjJfeiA9IG1lYW4oRjJfel90ZW1wTWlkKSwKICAgICAgICAgICAgICBtZWFuX0YxX2IgPSBtZWFuKEYxX2JfdGVtcE1pZCksCiAgICAgICAgICAgICAgbWVhbl9GMl9iID0gbWVhbihGMl9iX3RlbXBNaWQpKSAKICAKIyMjIFBsb3R0aW5nIFZTQQogICAgVlNBX2Nvb3JkcyA8LSBWU0FfY29vcmRzICU+JQogICAgICAgIGRwbHlyOjptdXRhdGUoVm93ZWwgPSBjYXNlX3doZW4oCiAgICAgICAgICBWb3dlbCA9PSAiYWUiIH4gIsOmIiwKICAgICAgICAgIFRSVUUgfiBWb3dlbAogICAgICAgICkpCiAgICAKICAgIFZTQXBsb3QgPC0gZ2dwbG90KGFlcyh4ID0gRjJfYiwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gRjFfYiksCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gRm9ybWFudHNfUFJBQVQsCiAgICAgICAgICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFKSArIAogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsCiAgICAgICAgICAgICAgICAgYWxwaGEgPSBmb3JtYW50QWxwaGEsCiAgICAgICAgICAgICAgICAgY29sb3IgPSBmb3JtYW50Q29sb3IpICsgCiAgICAgIGdlb21fcG9seWdvbihhZXMoeCA9IG1lYW5fRjJfYiwKICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9GMV9iKSwKICAgICAgICAgICAgICAgICAgIGRhdGEgPSBWU0FfY29vcmRzLAogICAgICAgICAgICAgICAgICAgYWxwaGEgPSBsaW5lQWxwaGEsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxpbmVDb2xvciwKICAgICAgICAgICAgICAgICAgIGZpbGw9TkEsCiAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgIGdlb21fcG9pbnQoYWVzKHggPSBtZWFuX0YyX2IsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBtZWFuX0YxX2IsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gVm93ZWwpLAogICAgICAgICAgICAgICAgIGRhdGEgPSBWU0FfY29vcmRzLAogICAgICAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDUpICsKICAgICAgc2NhbGVfeV9yZXZlcnNlKCkgKwogICAgICBzY2FsZV94X3JldmVyc2UoKSArCiAgICAgIGd1aWRlcyhjb2xvciA9IEZBTFNFKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArIGxhYnModGl0bGUgPSAiVlNBIikgKyB4bGFiKCJGMiAoQmFyaykiKSArIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpICsKICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJhIiA9ICIjMUFBRDc3IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICLDpiIgPSAiIzEyNzlCNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaSIgPSAiI0ZGQkYwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidSIgPSAiI0ZENzg1MyIpKQogICAgVlNBcGxvdAogIAogIHJtKFZTQV9jb29yZHMpCiAgCiMjIEh1bGwgLS0tLQojIyMgUGxvdHRpbmcgSHVsbAogICAgICBjb252ZXhDb29yZHMgPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgICAgZHBseXI6OnNlbGVjdChGMV9iLCBGMl9iKSAlPiUKICAgICAgICBhcy5tYXRyaXgoKSAlPiUKICAgICAgICBnckRldmljZXM6OmNodWxsKCkKICAgICAgY29udmV4IDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIHNsaWNlKGNvbnZleENvb3JkcykKCiAgICAgIGh1bGxQbG90IDwtIGdncGxvdChhZXMoRjJfYiwgRjFfYiksCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gRm9ybWFudHNfUFJBQVQpICsKICAgICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsCiAgICAgICAgICAgICAgICAgYWxwaGEgPSBmb3JtYW50QWxwaGEsCiAgICAgICAgICAgICAgICAgY29sb3IgPSBmb3JtYW50Q29sb3IpICsKICAgICAgICBnZW9tX3BvbHlnb24oZGF0YSA9IGNvbnZleCwKICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzEyNzlCNSIsCiAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgICBzY2FsZV94X3JldmVyc2UoKSArCiAgICAgICAgdGhlbWVfY2xhc3NpYygpICsgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24oIlZTQSJbSHVsbF0pKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIkYyIChCYXJrKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiRjEgKEJhcmspIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKICAgICAgaHVsbFBsb3QKICAgIAogIAojIyBWb3dlbCBTcGFjZSBEZW5zaXR5IC0tLS0KCiMgQmFyayBOb3JtYWxpemVkIERlbnNpdHkgLS0tLQojIHNlbGVjdGluZyB0aGUgYmFuZHdpZHRoCkhfaHBpIDwtIGtzOjpIcGkoeCA9IEZvcm1hbnRzX1BSQUFUWyxjKCJGMl9iIiwiRjFfYiIpXSwgcGlsb3QgPSAic2Ftc2UiLCBwcmUgPSAic2NhbGUiLCBiaW5uZWQgPSBUKQoKIyBjb21wdXRlIDJkIGtkZQprIDwtIGtkZSh4ID0gRm9ybWFudHNfUFJBQVRbLGMoIkYyX2IiLCJGMV9iIildLAogICAgICAgICBIID0gSF9ocGksCiAgICAgICAgIGJpbm5lZCA9IFQsCiAgICAgICAgIGdyaWRzaXplID0gMjUwKQoKI2RlbnNpdHkgPC0ga1tbImVzdGltYXRlIl1dCgojIEJlZm9yZSB3ZSBjYW4gcGxvdCB0aGUgZGVuc2l0eSBlc3RpbWF0ZSB3ZSBuZWVkIHRvIG1lbHQgaXQgaW50byBsb25nIGZvcm1hdAptYXQubWVsdGVkIDwtIGRhdGEudGFibGU6Om1lbHQoayRlc3RpbWF0ZSkKbmFtZXMobWF0Lm1lbHRlZCkgPC0gYygieCIsICJ5IiwgImRlbnNpdHkiKQoKIyBXZSBuZWVkIHRvIGFkZCB0d28gbW9yZSBjb2x1bXMgdG8gcHJlc2VydmUgdGhlIGF4ZXMgdW5pdHMKbWF0Lm1lbHRlZCRGMi5iIDwtIHJlcChrJGV2YWwucG9pbnRzW1sxXV0sIHRpbWVzID0gbnJvdyhrJGVzdGltYXRlKSkKbWF0Lm1lbHRlZCRGMS5iIDwtIHJlcChrJGV2YWwucG9pbnRzW1syXV0sIGVhY2ggPSBucm93KGskZXN0aW1hdGUpKQptYXQubWVsdGVkJGRlbnNpdHkgPC0gc2NhbGVzOjpyZXNjYWxlKG1hdC5tZWx0ZWQkZGVuc2l0eSwgdG8gPSBjKDAsIDEpKQoKIyBWU0QgLSAyNQpuVlNEXzI1IDwtIG1hdC5tZWx0ZWQgJT4lCiAgZHBseXI6OmZpbHRlcihkZW5zaXR5ID4gLjI1KSAlPiUKICBkcGx5cjo6c2VsZWN0KEYyLmIsRjEuYiwgZGVuc2l0eSkgJT4lCiAgZHBseXI6OnJlbmFtZShEZW5zaXR5ID0gZGVuc2l0eSkKCmNvbnZleENvb3JkcyA8LSBuVlNEXzI1ICU+JQogIGRwbHlyOjpzZWxlY3QoRjIuYiwgRjEuYikgJT4lCiAgYXMubWF0cml4KCkgJT4lCiAgI2dyRGV2aWNlczo6eHkuY29vcmRzKCkgJT4lCiAgZ3JEZXZpY2VzOjpjaHVsbCgpCm5jb252ZXhfMjUgPC0gblZTRF8yNSAlPiUKICBzbGljZShjb252ZXhDb29yZHMpCgojIFZTRCAtIDc1Cm5WU0RfNzUgPC0gbWF0Lm1lbHRlZCAlPiUKICBkcGx5cjo6ZmlsdGVyKGRlbnNpdHkgPiAuNzUpICU+JQogIGRwbHlyOjpzZWxlY3QoRjIuYixGMS5iLCBkZW5zaXR5KSAlPiUKICBkcGx5cjo6cmVuYW1lKERlbnNpdHkgPSBkZW5zaXR5KQoKY29udmV4Q29vcmRzIDwtIG5WU0RfNzUgJT4lCiAgZHBseXI6OnNlbGVjdChGMi5iLCBGMS5iKSAlPiUKICBhcy5tYXRyaXgoKSAlPiUKICBnckRldmljZXM6OmNodWxsKCkKbmNvbnZleF83NSA8LSBuVlNEXzc1ICU+JQogIHNsaWNlKGNvbnZleENvb3JkcykKCiMgUGxvdHRpbmcgWiBOb3JtYWxpemVkIFZTRCAKICAgIHJmIDwtIGNvbG9yUmFtcFBhbGV0dGUocmV2KFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCgxMSwgIlNwZWN0cmFsIikpKQogICAgciA8LSByZigzMikKICAgIAogICAgcGxvdERhdGEgPC0gbWF0Lm1lbHRlZCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnJlbmFtZShEZW5zaXR5ID0gZGVuc2l0eSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjptdXRhdGUoVlNEbGFiZWwgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICAgICAgICAgICAgICAgICAgICAgIERlbnNpdHkgPCAuMjUgfiAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgRGVuc2l0eSA+IC4yNSAmJiBEZW5zaXR5IDwgLjc1IH4gIlZTRDI1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlZTRDc1IgogICAgICAgICAgICAgICAgICAgICAgICApKQpnZW9tLnRleHQuc2l6ZSA8LSAyCiAgICBWU0RwbG90IDwtIGdncGxvdChkYXRhID0gcGxvdERhdGEsCiAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IEYyLmIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEYxLmIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IERlbnNpdHkpKSArIAogICAgICBnZW9tX3RpbGUoKSArIAogICAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKGV4cGFuZCA9IGMoMCwgMCksIAogICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcm91bmQoc2VxKG1pbihtYXQubWVsdGVkJEYyLmIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgobWF0Lm1lbHRlZCRGMi5iKSwgYnkgPSAyKSkpICsKICAgICAgc2NhbGVfeV9yZXZlcnNlKGV4cGFuZCA9IGMoMCwgMCksCiAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSByb3VuZChzZXEobWluKG1hdC5tZWx0ZWQkRjEuYiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KG1hdC5tZWx0ZWQkRjEuYiksIGJ5ID0gMikpKSArIAogICAgICB5bGFiKCJGMSAoQmFyaykiKSArIHhsYWIoIkYyIChCYXJrKSIpICsKICAgICAgbGFicyh0aXRsZSA9ICJWU0QiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxKSArCiAgICAgIGdlb21fcG9seWdvbihkYXRhID0gbmNvbnZleF8yNSwgYWxwaGEgPSBsaW5lQWxwaGEsIGNvbG9yID0gbGluZUNvbG9yLCBzaXplID0gMS41LCBmaWxsID0gTkEsIGxpbmV0eXBlID0gMikgKwogICAgICBnZW9tX3BvbHlnb24oZGF0YSA9IG5jb252ZXhfNzUsIGFscGhhID0gbGluZUFscGhhLCBjb2xvciA9IGxpbmVDb2xvciwgc2l6ZSA9IDEuNSwgZmlsbCA9IE5BLCBsaW5ldHlwZSA9IDEpICsKICAgICMgVlNEIDI1IExhYmVsCiAgICAgIGFubm90YXRlKGdlb20gPSAiY3VydmUiLAogICAgICAgICAgICAgICB4ID0gNi45LCB5ID0gMS43Ky41LAogICAgICAgICAgICAgICB4ZW5kID0gOC41LCB5ZW5kID0gMy41LAogICAgICAgICAgICAgICBjdXJ2YXR1cmUgPSAtLjMsCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAibW0iKSksCiAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIikgKwogICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLAogICAgICAgICAgICAgICB4ID0gNy41LCB5ID0gMS43LAogICAgICAgICAgICAgICBsYWJlbCA9IGRlcGFyc2UoYnF1b3RlKFZTRFsyNV0pKSwKICAgICAgICAgICAgICAgaGp1c3QgPSAiY2VudGVyIiwKICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwYXJzZT1UUlVFKSArCiAgICAjIFZTRCA3NSBMYWJlbAogICAgICBhbm5vdGF0ZShnZW9tID0gImN1cnZlIiwKICAgICAgICAgICAgICAgeCA9IDcuNSwgeSA9IDcuNS0uNSwKICAgICAgICAgICAgICAgeGVuZCA9IDExLjM1LCB5ZW5kID0gNS41LAogICAgICAgICAgICAgICBjdXJ2YXR1cmUgPSAuMywKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDIsICJtbSIpKSwKICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiKSArCiAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsCiAgICAgICAgICAgICAgIHggPSA3LCB5ID0gNy41LAogICAgICAgICAgICAgICBsYWJlbCA9IGRlcGFyc2UoYnF1b3RlKFZTRFs3NV0pKSwKICAgICAgICAgICAgICAgaGp1c3QgPSAiY2VudGVyIiwKICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICBwYXJzZSA9IFRSVUUpCiAgICAgVlNEcGxvdAoKIyBDb21iaW5lZCBQbG90CiAgICAgCiAgICAgcm93MSA8LSBWU0FwbG90ICsgQ0RwbG90ICsKICAgICAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JywKICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdyaWdodCcpCiAgICAgcm93MiA8LSBodWxsUGxvdCArIFZTRHBsb3QgKwogICAgICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnLAogICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpICYgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3JpZ2h0JykKICAgICAKICAgICBtZWFzdXJlc1Bsb3QgPC0gcm93MSAvIHJvdzIgKyBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEvMiwgMS8yKSwgYnlyb3cgPSBGQUxTRSkKICAgICBtZWFzdXJlc1Bsb3QKICAgICAKICAgICBybShyb3cxLCByb3cyKQoKZ2dzYXZlKGZpbGVuYW1lID0gIlBsb3RzL01lYXN1cmVzLnBuZyIsCiAgICAgICBwbG90ID0gbWVhc3VyZXNQbG90LAogICAgICAgaGVpZ2h0ID0gNS41LAogICAgICAgd2lkdGggPSA2LAogICAgICAgc2NhbGUgPSAuOCkKCmBgYAoKIyMgRmlsdGVyaW5nIFByb2Nlc3MKYGBge3J9CmZvcm1hbnRBbHBoYSA8LSAuMjAKbXlQYWwgPC0gYygiIzEyNzlCNSIsIiMyRDJEMzciKQoKUGl0Y2hfUFJBQVQgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwgc2VwID0gIiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLlBpdGNoIiwgaWdub3JlLmNhc2UgPSBUKSAlPiUKICAgIHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhLyIsLiwgc2VwID0gIiIpICU+JQogICAgcmVhZC5kZWxpbSguLCBoZWFkZXIgPSBGKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoUGl0Y2ggPSBWMSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKFBpdGNoID0gZ3N1YigiLS11bmRlZmluZWQtLSIsTkEsUGl0Y2gpLAogICAgICAgICAgICAgICAgICBQaXRjaCA9IGFzLm51bWVyaWMoUGl0Y2gpKQoKRm9ybWFudHNfUFJBQVQgPC0gbGlzdC5maWxlcyhwYXRoID0gcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJfRm9ybWFudCIsIGlnbm9yZS5jYXNlID0gVCkgJT4lCiAgICBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YS8iLC4sIHNlcCA9ICIiKSAlPiUKICAgIHJlYWQuZGVsaW0oLiwgaGVhZGVyID0gVCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KCFjKG5mb3JtYW50cywgQjEuSHouLCBCMi5Iei4sIEIzLkh6LiwgRjQuSHouLCBCNC5Iei4sIEY1Lkh6LiwgQjUuSHouKSkgJT4lCiAgICBkcGx5cjo6cmVuYW1lKFRpbWVfcyA9IHRpbWUucy4sCiAgICAgICAgICAgICAgICAgIEYxX0h6ID0gRjEuSHouLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IEYyLkh6LiwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBGMy5Iei4pICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9IeiA9IGlmZWxzZShGMV9IeiA9PSAwLCBOQSwgRjFfSHopLAogICAgICAgICAgICAgICAgICBGMl9IeiA9IGlmZWxzZShGMl9IeiA9PSAwLCBOQSwgRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19IeiA9IGlmZWxzZShGM19IeiA9PSAwLCBOQSwgRjNfSHopKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBhcy5udW1lcmljKEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBhcy5udW1lcmljKEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMoRjNfSHopKSwKICAgICAgICAgICAgICAgICAgVGltZV9tcyA9IFRpbWVfcyAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYxX2tIeiA9IEYxX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjJfa0h6ID0gRjJfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGM19rSHogPSBGM19IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYxX2IgPSBlbXVSOjpiYXJrKEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfYiA9IGVtdVI6OmJhcmsoRjJfSHopLAogICAgICAgICAgICAgICAgICBGM19iID0gZW11Ujo6YmFyayhGM19IeikpICU+JQogICAgZHBseXI6OnNlbGVjdCghVGltZV9zKSAlPiUKICAgIGRwbHlyOjpyZWxvY2F0ZShUaW1lX21zLCAuYmVmb3JlID0gRjFfSHopICU+JQogICAgY2JpbmQoLixQaXRjaF9QUkFBVCkKICAKICBjIDwtIDIKICB3aGlsZShjIDwgTlJPVyhGb3JtYW50c19QUkFBVCkpewogICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSkKICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10pCiAgICBjIDwtIGMgKyAxCiAgfQogIHJtKGMpCiAgCiAgIyBSYXcgRm9ybWFudHMgLS0tLQogIGYxIDwtIGdncGxvdChhZXMoeD1GMl9iLAogICAgICAgICAgICAgICAgICAgeT1GMV9iKSwKICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFUKSArIAogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGNvbG9yID0gbXlQYWxbMl0pICsKICAgICAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoMTYsMCkpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKGxpbWl0cyA9IGMoMTksMykpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15UGFsKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiUmF3IEZvcm1hbnRcblZhbHVlcyIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKICAgIAojIFN0ZXAgIzE6IFZvaWNlZCBTZWdtZW50cyAtLS0tCiAgICBwbG90RGF0YSA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICAgICAgICAgICAgIGRwbHlyOjptdXRhdGUoaXNPdXRsaWVyID0gY2FzZV93aGVuKAogICAgICAgICAgICAgICAgICAgICBpcy5uYShQaXRjaCkgfiAiUmVtb3ZlZCIsCiAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiUmV0YWluZWQiCiAgICAgICAgICAgICAgICAgICApKQogICAgZjIgPC0gZ2dwbG90KGRhdGEgPSBwbG90RGF0YSwKICAgICAgICAgICAgICAgICBhZXMoeCA9IEYyX2IsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBGMV9iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGlzT3V0bGllcikpICsgCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZGF0YSA9IHBsb3REYXRhICU+JQogICAgICAgICAgICAgICAgICAgZHBseXI6OmZpbHRlcihpc091dGxpZXIgPT0gIlJlbW92ZWQiKSkgKwogICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGRhdGEgPSBwbG90RGF0YSAlPiUKICAgICAgICAgICAgIGRwbHlyOjpmaWx0ZXIoaXNPdXRsaWVyID09ICJSZXRhaW5lZCIpKSArCiAgICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKDE2LDApKSArCiAgICAgIHNjYWxlX3hfcmV2ZXJzZShsaW1pdHMgPSBjKDE5LDMpKSArCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIlZvaWNlZCBTZWdtZW50cyIpKSArCiAgICAgIHhsYWIoIkYyIChCYXJrKSIpICsKICAgICAgeWxhYigiRjEgKEJhcmspIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkKICAgIAojIFN0ZXAgMjogTUFEIC0tLS0KICAgIHBsb3REYXRhIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShQaXRjaCkpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKEYxX21hZCA9IChhYnMoRjFfSHogLSBtZWRpYW4oRjFfSHopKS8gbWFkKEYxX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41LAogICAgICAgICAgICAgICAgICAgIGlzT3V0bGllciA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICAgIEYxX21hZCA9PSBUUlVFIHwgRjJfbWFkID09IFRSVUUgfiAiUmVtb3ZlZCIsCiAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIlJldGFpbmVkIgogICAgICAgICAgICAgICApKQogICAgCiAgICBmMyA8LSBnZ3Bsb3QoZGF0YSA9IHBsb3REYXRhLAogICAgICAgICAgICAgICAgIGFlcyh4ID0gRjJfYiwKICAgICAgICAgICAgICAgICAgICAgeSA9IEYxX2IsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gaXNPdXRsaWVyKSkgKyAKICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBkYXRhID0gcGxvdERhdGEgJT4lCiAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGlzT3V0bGllciA9PSAiUmVtb3ZlZCIpKSArCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZGF0YSA9IHBsb3REYXRhICU+JQogICAgICAgICAgICAgZHBseXI6OmZpbHRlcihpc091dGxpZXIgPT0gIlJldGFpbmVkIikpICsKICAgICAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoMTYsMCkpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKGxpbWl0cyA9IGMoMTksMykpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15UGFsKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiTWVkaWFuIEFic29sdXRlXG5EZXZpYXRpb24iKSkgKwogICAgICB4bGFiKCJGMiAoQmFyaykiKSArCiAgICAgIHlsYWIoIkYxIChCYXJrKSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpCiAgICAKIyBTdGVwIDM6IE1haGFsYW5ob2JpcyBEaXN0YW5jZSAtLS0tCiAgcGxvdERhdGEgPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFBpdGNoKSkgJT4lCiAgICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgICAgRjJfbWFkID0gKGFicyhGMl9IeiAtIG1lZGlhbihGMl9IeikpLyBtYWQoRjJfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUpICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKEYxX21hZCA9PSBGQUxTRSAmIEYyX21hZCA9PSBGQUxTRSkgJT4lCiAgICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSwKICAgICAgICAgICAgICAgICAgaXNPdXRsaWVyID0gY2FzZV93aGVuKAogICAgICAgICAgICAgICAgICAgIG1EaXN0X3NkIDwgMiB+ICJSZXRhaW5lZCIsCiAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJSZW1vdmVkIgogICAgICAgICAgICAgICAgICApKQogICAgCiAgICBmNCA8LSBnZ3Bsb3QoZGF0YSA9IHBsb3REYXRhLAogICAgICAgICAgICAgICAgIGFlcyh4ID0gRjJfYiwKICAgICAgICAgICAgICAgICAgICAgeSA9IEYxX2IsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gaXNPdXRsaWVyKSkgKyAKICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBkYXRhID0gcGxvdERhdGEgJT4lCiAgICAgICAgICAgICAgICAgICBkcGx5cjo6ZmlsdGVyKGlzT3V0bGllciA9PSAiUmVtb3ZlZCIpKSArCiAgICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgZGF0YSA9IHBsb3REYXRhICU+JQogICAgICAgICAgICAgZHBseXI6OmZpbHRlcihpc091dGxpZXIgPT0gIlJldGFpbmVkIikpICsKICAgICAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoMTYsMCkpICsKICAgICAgc2NhbGVfeF9yZXZlcnNlKGxpbWl0cyA9IGMoMTksMykpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15UGFsKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiTWFoYWxhbm9iaXNcbkRpc3RhbmNlIikpICsgeGxhYigiRjIgKEJhcmspIikgKyB5bGFiKCJGMSAoQmFyaykiKSArCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICBhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKQogICAgCiMgRmluYWwgRm9ybWFudHMgLS0tLQogICAgcGxvdERhdGEgPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShQaXRjaCkpICU+JQogICAgZHBseXI6Om11dGF0ZShGMV9tYWQgPSAoYWJzKEYxX0h6IC0gbWVkaWFuKEYxX0h6KSkvIG1hZChGMV9IeiwgY29uc3RhbnQgPSAxLjQ4MjYpKSA+IDIuNSwKICAgICAgICAgICAgICAgICAgRjJfbWFkID0gKGFicyhGMl9IeiAtIG1lZGlhbihGMl9IeikpLyBtYWQoRjJfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUpICU+JQogICAgZHBseXI6OmZpbHRlcihGMV9tYWQgPT0gRkFMU0UgJiBGMl9tYWQgPT0gRkFMU0UpICU+JQogICAgZHBseXI6Om11dGF0ZShtRGlzdCA9IG1haGFsYW5vYmlzKGNiaW5kKC4kRjFfSHosIC4kRjJfSHopLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbE1lYW5zKGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3YgPSBjb3YoY2JpbmQoLiRGMV9IeiwgLiRGMl9IeikpKSwKICAgICAgICAgICAgICAgICAgbURpc3Rfc2QgPSBhYnMoc2NhbGUobURpc3QsY2VudGVyID0gVCkpKSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIobURpc3Rfc2QgPCAyKQogICAgCiAgICBmNSA8LSBnZ3Bsb3QoYWVzKHg9RjJfYiwKICAgICAgICAgICAgICAgICAgICAgeT1GMV9iKSwKICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gcGxvdERhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKyAKICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvciA9IG15UGFsWzJdKSArIAogICAgICBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYygxNiwwKSkgKwogICAgICBzY2FsZV94X3JldmVyc2UobGltaXRzID0gYygxOSwzKSkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIkZpbmFsIEZvcm1hbnRcblRyYWplY3RvcmllcyIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQogICAgCiMgQ29taWJpbmcgcGxvdHMKICAgIGZpbHRlcmVkUGxvdCA8LSBmMSArIGYyICsgZjMgKyBmNCArIGY1ICsgcGF0Y2h3b3JrOjpndWlkZV9hcmVhKCkgKwogICAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JywKICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzKSArCiAgICAgIHBhdGNod29yazo6cGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnQScpCiAgICBmaWx0ZXJlZFBsb3QKICAgIAogICAgZ2dzYXZlKHBsb3QgPSBmaWx0ZXJlZFBsb3QsICJQbG90cy9GaWx0ZXJlZCBGb3JtYW50cy5wbmciLAogICAgICAgICAgIGhlaWdodCA9IDYsCiAgICAgICAgICAgd2lkdGggPSA4LAogICAgICAgICAgIHVuaXRzID0gImluIiwKICAgICAgICAgICBzY2FsZSA9IC44NSkKICAKYGBgCgojIyBPVCB2cy4gVkFTCmBgYHtyfQpwbG90RGF0YV9JbnQgPC0gQWNvdXN0aWNEYXRhICU+JQogIGRwbHlyOjpmaWx0ZXIoIWdyZXBsKCJfcmVsIiwgU3BlYWtlcikpICU+JQogIGRwbHlyOjpncm91cF9ieShTcGVha2VyKSAlPiUKICBkcGx5cjo6bXV0YXRlKHNlZ01pbiA9IGJhc2U6Om1pbihWQVMsIHRyYW5zQWNjKSwKICAgICAgICAgICAgICAgIHNlZ01heCA9IGJhc2U6Om1heChWQVMsIHRyYW5zQWNjKSwKICAgICAgICAgICAgICAgIHJhdGluZ0F2ZyA9IG1lYW4oVkFTLCB0cmFuc0FjYywgbmEucm0gPSBUKSwKICAgICAgICAgICAgICAgIFNwZWFrZXIgPSBhcy5mYWN0b3IoU3BlYWtlciksCiAgICAgICAgICAgICAgICBFdGlvbG9neSA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgRXRpb2xvZ3kgPT0gIkF0YXhpYyIgfiAiQXRheGlhIiwKICAgICAgICAgICAgICAgICAgVFJVRSB+IGFzLmNoYXJhY3RlcihFdGlvbG9neSkKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICBFdGlvbG9neSA9IGFzLmZhY3RvcihFdGlvbG9neSkpICU+JQogIGFycmFuZ2Uoc2VnTWF4KQoKbXlfcGFsIDwtIGMoIiNmMjY0MzAiLCAiIzI3MkQyRCIsIiMyNTZlZmYiKQojIFdpdGggYSBiaXQgbW9yZSBzdHlsZQpwbG90X0ludCA8LSBnZ3Bsb3QocGxvdERhdGFfSW50KSArCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gZmN0X2lub3JkZXIoU3BlYWtlciksCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gU3BlYWtlciwKICAgICAgICAgICAgICAgICAgIHkgPSBzZWdNaW4sCiAgICAgICAgICAgICAgICAgICB5ZW5kID0gc2VnTWF4LAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBFdGlvbG9neSkpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gU3BlYWtlciwKICAgICAgICAgICAgICAgICB5ID0gVkFTLAogICAgICAgICAgICAgICAgIGNvbG9yID0gRXRpb2xvZ3kpLAogICAgICAgICAgICAgI2NvbG9yID0gbXlfcGFsWzFdLAogICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICBzaGFwZSA9IDE5KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IFNwZWFrZXIsCiAgICAgICAgICAgICAgICAgeSA9IHRyYW5zQWNjLAogICAgICAgICAgICAgICAgIGNvbG9yID0gRXRpb2xvZ3kpLAogICAgICAgICAgICAgI2NvbG9yID0gbXlfcGFsWzJdLAogICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICBzaGFwZSA9IDE1KSArCiAgY29vcmRfZmxpcCgpKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgKSArCiAgeGxhYigiIikgKwogIHlsYWIoIlNwZWVjaCBJbnRlbGxpZ2liaWxpdHkiKSArCiAgZ2d0aXRsZSgiU3BlZWNoIEludGVsbGlnaWJpbGl0eSIpICsKICB5bGltKGMoMCwxMDApKQoKCm15UGFsIDwtIGMoIiMxQUFENzciLCAiIzEyNzlCNSIsICIjRkZCRjAwIiwgIiNGRDc4NTMiLCAiI0JGMzE3OCIpCm15U2hhcGVzIDwtIGMoMTYsIDE4LCAxNywgMTUpCgpPVF9WQVNzY2F0dGVyIDwtIGdncGxvdChwbG90RGF0YV9JbnQsCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gVkFTLAogICAgICAgICAgICAgICAgICAgICAgeSA9IHRyYW5zQWNjLAogICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBFdGlvbG9neSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gRXRpb2xvZ3ksCiAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IEV0aW9sb2d5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGKSArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMTAwKSwgeWxpbSA9IGMoMCwxMDApKSArCiAgbGFicyh4ID0gIkludGVsbGlnaWJpbGl0eSAoVkFTKSIsIHkgPSAiSW50ZWxsaWdpYmlsaXR5IChPVCkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15UGFsKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IG15U2hhcGVzKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShhc3BlY3QucmF0aW89MSwKICAgICAgICBsZWdlbmQucG9zaXRpb249InJpZ2h0IikKCgpnZ3NhdmUoZmlsZW5hbWUgPSAiUGxvdHMvT1QgYW5kIFZBUyBTY2F0dGVycGxvdC5wbmciLAogICAgICAgcGxvdCA9IE9UX1ZBU3NjYXR0ZXIsCiAgICAgICBoZWlnaHQgPSAzLjI1LAogICAgICAgd2lkdGggPSA0LAogICAgICAgdW5pdHMgPSAiaW4iLAogICAgICAgc2NhbGUgPSAxKQoKcm0oc2NhdHRlcjEsIHNjYXR0ZXIyLCBjb21iaW5lZFNjYXR0ZXIpCmBgYAoKIyMgTW9kZWwgU2NhdHRlcnBsb3RzCmBgYHtyfQptb2RlbEZpZ3VyZURhdGEgPC0gQWNvdXN0aWNEYXRhICU+JQogIGRwbHlyOjpmaWx0ZXIoIWdyZXBsKCJfcmVsIixTcGVha2VyKSkgJT4lCiAgZHBseXI6OnNlbGVjdChTcGVha2VyLCBFdGlvbG9neSwgU2V4LCBWU0FfYiwgdm93ZWxfRURfYiwgSHVsbF9iLCBIdWxsX2JWU0RfMjUsIEh1bGxfYlZTRF83NSwgVkFTLCB0cmFuc0FjYykgJT4lCiAgZHBseXI6Om11dGF0ZShTcGVha2VyID0gYXMuZmFjdG9yKFNwZWFrZXIpLAogICAgICAgICAgICAgICAgRXRpb2xvZ3kgPSBhcy5mYWN0b3IoRXRpb2xvZ3kpLAogICAgICAgICAgICAgICAgU2V4ID0gYXMuZmFjdG9yKFNleCkpICU+JQogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IFZBUzp0cmFuc0FjYywgbmFtZXNfdG8gPSAiSW50VHlwZSIsIHZhbHVlc190byA9ICJJbnQiKSAlPiUKICBkcGx5cjo6bXV0YXRlKEludFR5cGUgPSBjYXNlX3doZW4oCiAgICBJbnRUeXBlID09ICJ0cmFuc0FjYyIgfiAiT1QiLAogICAgVFJVRSB+ICJWQVMiCiAgKSwKICAgICAgICAgICAgICAgIEludFR5cGUgPSBhcy5mYWN0b3IoSW50VHlwZSkpCgp5bGFiZWwgPC0gIkludGVsbGlnaWJpbGl0eSIKbXlQYWwgPC0gYygiIzJEMkQzNyIsICIjMTI3OUI1IikKbXlQYWxTaGFwZSA8LSBjKDE5LCAxKQoKVlNBIDwtIG1vZGVsRmlndXJlRGF0YSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBWU0FfYiwKICAgICAgeSA9IEludCwKICAgICAgY29sb3IgPSBJbnRUeXBlLAogICAgICBzaGFwZSA9IEludFR5cGUsCiAgICAgIGxpbmV0eXBlID0gSW50VHlwZSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULCBmaWxsID0gImxpZ2h0IGdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGKSArCiAgeGxhYihleHByZXNzaW9uKCJWU0EgKEJhcmsiXjIqIikiKSkgKwogIHlsYWIoeWxhYmVsKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsMTAwKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXNwZWN0LnJhdGlvPTEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXlQYWwpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gbXlQYWxTaGFwZSkgKwogIGxhYnMoY29sb3I9IkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIHNoYXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIiwKICAgICAgIGxpbmV0eXBlID0gIkludGVsbGlnaWJpbGl0eSBUeXBlIikKCmRpc3AgPC0gbW9kZWxGaWd1cmVEYXRhICU+JQogIGdncGxvdCgpICsKICBhZXMoeCA9IHZvd2VsX0VEX2IsCiAgICAgIHkgPSBJbnQsCiAgICAgIGNvbG9yID0gSW50VHlwZSwKICAgICAgc2hhcGUgPSBJbnRUeXBlLAogICAgICBsaW5ldHlwZSA9IEludFR5cGUpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwgZmlsbCA9ICJsaWdodCBncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKwogIHhsYWIoIkNvcm5lciBEaXNwZXJzaW9uIChCYXJrKSIpICsKICB5bGFiKHlsYWJlbCkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGFzcGVjdC5yYXRpbz0xKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15UGFsKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IG15UGFsU2hhcGUpICsKICBsYWJzKGNvbG9yPSJJbnRlbGxpZ2liaWxpdHkgVHlwZSIsCiAgICAgICBzaGFwZSA9ICJJbnRlbGxpZ2liaWxpdHkgVHlwZSIsCiAgICAgICBsaW5ldHlwZSA9ICJJbnRlbGxpZ2liaWxpdHkgVHlwZSIpCgpIdWxsIDwtIG1vZGVsRmlndXJlRGF0YSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBIdWxsX2IsCiAgICAgIHkgPSBJbnQsCiAgICAgIGNvbG9yID0gSW50VHlwZSwKICAgICAgc2hhcGUgPSBJbnRUeXBlLAogICAgICBsaW5ldHlwZSA9IEludFR5cGUpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwgZmlsbCA9ICJsaWdodCBncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRikgKwogIHhsYWIoZXhwcmVzc2lvbigiVlNBIltIdWxsXSoiIChCYXJrIl4yKiIpIikpICsKICB5bGFiKHlsYWJlbCkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGFzcGVjdC5yYXRpbz0xKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBteVBhbFNoYXBlKSArCiAgbGFicyhjb2xvcj0iSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgc2hhcGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgbGluZXR5cGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiKQoKdnNkMjUgPC0gbW9kZWxGaWd1cmVEYXRhICU+JQogIGdncGxvdCgpICsKICBhZXMoeCA9IEh1bGxfYlZTRF8yNSwKICAgICAgeSA9IEludCwKICAgICAgY29sb3IgPSBJbnRUeXBlLAogICAgICBzaGFwZSA9IEludFR5cGUsCiAgICAgIGxpbmV0eXBlID0gSW50VHlwZSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULCBmaWxsID0gImxpZ2h0IGdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGKSArCiAgeGxhYihleHByZXNzaW9uKCJWU0QiWzI1XSoiIChCYXJrIl4yKiIpIikpICsKICB5bGFiKHlsYWJlbCkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGFzcGVjdC5yYXRpbz0xKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBteVBhbFNoYXBlKSArCiAgbGFicyhjb2xvcj0iSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgc2hhcGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgbGluZXR5cGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiKQoKdnNkNzUgPC0gbW9kZWxGaWd1cmVEYXRhICU+JQogIGdncGxvdCgpICsKICBhZXMoeCA9IEh1bGxfYlZTRF83NSwKICAgICAgeSA9IEludCwKICAgICAgY29sb3IgPSBJbnRUeXBlLAogICAgICBzaGFwZSA9IEludFR5cGUsCiAgICAgIGxpbmV0eXBlID0gSW50VHlwZSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULCBmaWxsID0gImxpZ2h0IGdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGKSArCiAgeGxhYihleHByZXNzaW9uKCJWU0QiWzc1XSoiIChCYXJrIl4yKiIpIikpICsKICB5bGFiKHlsYWJlbCkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGFzcGVjdC5yYXRpbz0xKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteVBhbCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBteVBhbFNoYXBlKSArCiAgbGFicyhjb2xvcj0iSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgc2hhcGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiLAogICAgICAgbGluZXR5cGUgPSAiSW50ZWxsaWdpYmlsaXR5IFR5cGUiKQoKIyBDcmVhdGluZyBPVCBTY2F0dGVycGxvdCBGaWd1cmUKCnNjYXR0ZXIgPC0gVlNBICArIGRpc3AgKyBwYXRjaHdvcms6Omd1aWRlX2FyZWEoKSArIEh1bGwgKyB2c2QyNSArIHZzZDc1ICsKICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JywKICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCnNjYXR0ZXIgCgpnZ3NhdmUoIlBsb3RzL01vZGVsRmlndXJlLnBuZyIsIHNjYXR0ZXIsCiAgICAgICBoZWlnaHQgPSA0LAogICAgICAgd2lkdGggPSA2LAogICAgICAgdW5pdHMgPSAiaW4iLAogICAgICAgc2NhbGUgPSAxLjEpCmBgYAoKIyMgRmlsdGVyaW5nIGF0IERpZmZlcmVudCBMZXZlbHMKYGBge3J9CnRleHRfeCA8LSAxMi41CnRleHRfeSA8LSA4LjUKeGxpbXMgPC0gYygxNiw1KQp5bGltcyA8LSBjKDksMSkKIyBIdWxsIC0gMiBTRCAtLS0tClBpdGNoX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhIiwgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIuUGl0Y2giLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IEYpICU+JQogICAgZHBseXI6OnJlbmFtZShQaXRjaCA9IFYxKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoUGl0Y2ggPSBnc3ViKCItLXVuZGVmaW5lZC0tIixOQSxQaXRjaCksCiAgICAgICAgICAgICAgICAgIFBpdGNoID0gYXMubnVtZXJpYyhQaXRjaCkpCgpGb3JtYW50c19QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiX0Zvcm1hbnQiLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IFQpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhuZm9ybWFudHMsIEIxLkh6LiwgQjIuSHouLCBCMy5Iei4sIEY0Lkh6LiwgQjQuSHouLCBGNS5Iei4sIEI1Lkh6LikpICU+JQogICAgZHBseXI6OnJlbmFtZShUaW1lX3MgPSB0aW1lLnMuLAogICAgICAgICAgICAgICAgICBGMV9IeiA9IEYxLkh6LiwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBGMi5Iei4sCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gRjMuSHouKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBpZmVsc2UoRjFfSHogPT0gMCwgTkEsIEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBpZmVsc2UoRjJfSHogPT0gMCwgTkEsIEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBpZmVsc2UoRjNfSHogPT0gMCwgTkEsIEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gYXMubnVtZXJpYyhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gYXMubnVtZXJpYyhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKEYzX0h6KSksCiAgICAgICAgICAgICAgICAgIFRpbWVfbXMgPSBUaW1lX3MgLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9rSHogPSBGMV9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYyX2tIeiA9IEYyX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjNfa0h6ID0gRjNfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9iID0gZW11Ujo6YmFyayhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX2IgPSBlbXVSOjpiYXJrKEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfYiA9IGVtdVI6OmJhcmsoRjNfSHopKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIVRpbWVfcykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVGltZV9tcywgLmJlZm9yZSA9IEYxX0h6KSAlPiUKICAgIGNiaW5kKC4sUGl0Y2hfUFJBQVQpICU+JQogICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoRjFfbWFkID09IEZBTFNFICYgRjJfbWFkID09IEZBTFNFKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSkgJT4lCiAgICAjZHBseXI6Om11dGF0ZShtRGlzdE91dGxpZXIgPSAoc3RhdHM6OnBjaGlzcShtRGlzdCwgZGY9MSwgbG93ZXIudGFpbD1GQUxTRSkpIDwgLjAwMSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG1EaXN0X3NkIDwgMikKICAKICBjIDwtIDIKICB3aGlsZShjIDwgTlJPVyhGb3JtYW50c19QUkFBVCkpewogICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSkKICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10pCiAgICBjIDwtIGMgKyAxCiAgfQogIHJtKGMpCiAgCiAgICBIdWxsX2IgPC0gY0h1bGwoRm9ybWFudHNfUFJBQVQkRjFfYiwgRm9ybWFudHNfUFJBQVQkRjJfYikKIyMjIFBsb3R0aW5nIEh1bGwKICAgICAgY29udmV4Q29vcmRzIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIGRwbHlyOjpzZWxlY3QoRjFfYiwgRjJfYikgJT4lCiAgICAgICAgYXMubWF0cml4KCkgJT4lCiAgICAgICAgZ3JEZXZpY2VzOjpjaHVsbCgpCiAgICAgIGNvbnZleCA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBzbGljZShjb252ZXhDb29yZHMpCgogICAgICBodWxsUGxvdF8yIDwtIGdncGxvdChhZXMoRjJfYiwgRjFfYiksCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gRm9ybWFudHNfUFJBQVQpICsKICAgICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEpICsKICAgICAgICBnZW9tX3BvbHlnb24oZGF0YSA9IGNvbnZleCwKICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzEyNzlCNSIsCiAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IHRleHRfeCwgeSA9IHRleHRfeSwgbGFiZWwgPSBwYXN0ZSgiSHVsbCA9Iixyb3VuZChIdWxsX2IsMikpKSArCiAgICAgICAgc2NhbGVfeV9yZXZlcnNlKCkgKwogICAgICAgIHNjYWxlX3hfcmV2ZXJzZSgpICsKICAgICAgICB4bGltKHhsaW1zKSArCiAgICAgICAgeWxpbSh5bGltcykgKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiMiBTRCIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpCiAgICAgIGh1bGxQbG90XzIKICAgICAgCiMgSHVsbCAtIDIuNSBTRCAtLS0tClBpdGNoX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhIiwgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIuUGl0Y2giLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IEYpICU+JQogICAgZHBseXI6OnJlbmFtZShQaXRjaCA9IFYxKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoUGl0Y2ggPSBnc3ViKCItLXVuZGVmaW5lZC0tIixOQSxQaXRjaCksCiAgICAgICAgICAgICAgICAgIFBpdGNoID0gYXMubnVtZXJpYyhQaXRjaCkpCgpGb3JtYW50c19QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiX0Zvcm1hbnQiLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IFQpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhuZm9ybWFudHMsIEIxLkh6LiwgQjIuSHouLCBCMy5Iei4sIEY0Lkh6LiwgQjQuSHouLCBGNS5Iei4sIEI1Lkh6LikpICU+JQogICAgZHBseXI6OnJlbmFtZShUaW1lX3MgPSB0aW1lLnMuLAogICAgICAgICAgICAgICAgICBGMV9IeiA9IEYxLkh6LiwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBGMi5Iei4sCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gRjMuSHouKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBpZmVsc2UoRjFfSHogPT0gMCwgTkEsIEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBpZmVsc2UoRjJfSHogPT0gMCwgTkEsIEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBpZmVsc2UoRjNfSHogPT0gMCwgTkEsIEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gYXMubnVtZXJpYyhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gYXMubnVtZXJpYyhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKEYzX0h6KSksCiAgICAgICAgICAgICAgICAgIFRpbWVfbXMgPSBUaW1lX3MgLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9rSHogPSBGMV9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYyX2tIeiA9IEYyX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjNfa0h6ID0gRjNfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9iID0gZW11Ujo6YmFyayhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX2IgPSBlbXVSOjpiYXJrKEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfYiA9IGVtdVI6OmJhcmsoRjNfSHopKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIVRpbWVfcykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVGltZV9tcywgLmJlZm9yZSA9IEYxX0h6KSAlPiUKICAgIGNiaW5kKC4sUGl0Y2hfUFJBQVQpICU+JQogICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoRjFfbWFkID09IEZBTFNFICYgRjJfbWFkID09IEZBTFNFKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSkgJT4lCiAgICAjZHBseXI6Om11dGF0ZShtRGlzdE91dGxpZXIgPSAoc3RhdHM6OnBjaGlzcShtRGlzdCwgZGY9MSwgbG93ZXIudGFpbD1GQUxTRSkpIDwgLjAwMSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG1EaXN0X3NkIDwgMi41KQogIAogIGMgPC0gMgogIHdoaWxlKGMgPCBOUk9XKEZvcm1hbnRzX1BSQUFUKSl7CiAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdKQogICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSkKICAgIGMgPC0gYyArIDEKICB9CiAgcm0oYykKICAKICAgIEh1bGxfYiA8LSBjSHVsbChGb3JtYW50c19QUkFBVCRGMV9iLCBGb3JtYW50c19QUkFBVCRGMl9iKQojIyMgUGxvdHRpbmcgSHVsbAogICAgICBjb252ZXhDb29yZHMgPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgICAgZHBseXI6OnNlbGVjdChGMV9iLCBGMl9iKSAlPiUKICAgICAgICBhcy5tYXRyaXgoKSAlPiUKICAgICAgICBnckRldmljZXM6OmNodWxsKCkKICAgICAgY29udmV4IDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIHNsaWNlKGNvbnZleENvb3JkcykKCiAgICAgIGh1bGxQbG90XzIuNSA8LSBnZ3Bsb3QoYWVzKEYyX2IsIEYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFUKSArCiAgICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxKSArCiAgICAgICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBjb252ZXgsCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjUsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpICsKICAgICAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSB0ZXh0X3gsIHkgPSB0ZXh0X3ksIGxhYmVsID0gcGFzdGUoIkh1bGwgPSIscm91bmQoSHVsbF9iLDIpKSkgKwogICAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgICBzY2FsZV94X3JldmVyc2UoKSArCiAgICAgICAgeGxpbSh4bGltcykgKwogICAgICAgIHlsaW0oeWxpbXMpICsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIjIuNSBTRCIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpCiAgICAgIGh1bGxQbG90XzIuNQogICAgICAKIyBIdWxsIC0gMyBTRCAtLS0tClBpdGNoX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhIiwgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIuUGl0Y2giLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IEYpICU+JQogICAgZHBseXI6OnJlbmFtZShQaXRjaCA9IFYxKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoUGl0Y2ggPSBnc3ViKCItLXVuZGVmaW5lZC0tIixOQSxQaXRjaCksCiAgICAgICAgICAgICAgICAgIFBpdGNoID0gYXMubnVtZXJpYyhQaXRjaCkpCgpGb3JtYW50c19QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiX0Zvcm1hbnQiLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IFQpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhuZm9ybWFudHMsIEIxLkh6LiwgQjIuSHouLCBCMy5Iei4sIEY0Lkh6LiwgQjQuSHouLCBGNS5Iei4sIEI1Lkh6LikpICU+JQogICAgZHBseXI6OnJlbmFtZShUaW1lX3MgPSB0aW1lLnMuLAogICAgICAgICAgICAgICAgICBGMV9IeiA9IEYxLkh6LiwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBGMi5Iei4sCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gRjMuSHouKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBpZmVsc2UoRjFfSHogPT0gMCwgTkEsIEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBpZmVsc2UoRjJfSHogPT0gMCwgTkEsIEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBpZmVsc2UoRjNfSHogPT0gMCwgTkEsIEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gYXMubnVtZXJpYyhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gYXMubnVtZXJpYyhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKEYzX0h6KSksCiAgICAgICAgICAgICAgICAgIFRpbWVfbXMgPSBUaW1lX3MgLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9rSHogPSBGMV9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYyX2tIeiA9IEYyX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjNfa0h6ID0gRjNfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9iID0gZW11Ujo6YmFyayhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX2IgPSBlbXVSOjpiYXJrKEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfYiA9IGVtdVI6OmJhcmsoRjNfSHopKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIVRpbWVfcykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVGltZV9tcywgLmJlZm9yZSA9IEYxX0h6KSAlPiUKICAgIGNiaW5kKC4sUGl0Y2hfUFJBQVQpICU+JQogICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoRjFfbWFkID09IEZBTFNFICYgRjJfbWFkID09IEZBTFNFKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSkgJT4lCiAgICAjZHBseXI6Om11dGF0ZShtRGlzdE91dGxpZXIgPSAoc3RhdHM6OnBjaGlzcShtRGlzdCwgZGY9MSwgbG93ZXIudGFpbD1GQUxTRSkpIDwgLjAwMSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG1EaXN0X3NkIDwgMykKICAKICBjIDwtIDIKICB3aGlsZShjIDwgTlJPVyhGb3JtYW50c19QUkFBVCkpewogICAgRm9ybWFudHNfUFJBQVQkRjFfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMV9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSkKICAgIEZvcm1hbnRzX1BSQUFUJEYyX0h6W2NdIDwtIGlmZWxzZShpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjLTFdKSAmJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoRm9ybWFudHNfUFJBQVQkRjJfSHpbYysxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10pCiAgICBjIDwtIGMgKyAxCiAgfQogIHJtKGMpCiAgCiAgICBIdWxsX2IgPC0gY0h1bGwoRm9ybWFudHNfUFJBQVQkRjFfYiwgRm9ybWFudHNfUFJBQVQkRjJfYikKIyMjIFBsb3R0aW5nIEh1bGwKICAgICAgY29udmV4Q29vcmRzIDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIGRwbHlyOjpzZWxlY3QoRjFfYiwgRjJfYikgJT4lCiAgICAgICAgYXMubWF0cml4KCkgJT4lCiAgICAgICAgZ3JEZXZpY2VzOjpjaHVsbCgpCiAgICAgIGNvbnZleCA8LSBGb3JtYW50c19QUkFBVCAlPiUKICAgICAgICBzbGljZShjb252ZXhDb29yZHMpCgogICAgICBodWxsUGxvdF8zIDwtIGdncGxvdChhZXMoRjJfYiwgRjFfYiksCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gRm9ybWFudHNfUFJBQVQpICsKICAgICAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEpICsKICAgICAgICBnZW9tX3BvbHlnb24oZGF0YSA9IGNvbnZleCwKICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNSwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzEyNzlCNSIsCiAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IHRleHRfeCwgeSA9IHRleHRfeSwgbGFiZWwgPSBwYXN0ZSgiSHVsbCA9Iixyb3VuZChIdWxsX2IsMikpKSArCiAgICAgICAgc2NhbGVfeV9yZXZlcnNlKCkgKwogICAgICAgIHNjYWxlX3hfcmV2ZXJzZSgpICsKICAgICAgICB4bGltKHhsaW1zKSArCiAgICAgICAgeWxpbSh5bGltcykgKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiMyBTRCIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpCiAgICAgIGh1bGxQbG90XzMKICAgICAgCiMgSHVsbCAtIDEuNSBTRCAtLS0tClBpdGNoX1BSQUFUIDwtIGxpc3QuZmlsZXMocGF0aCA9IHBhc3RlKCJQcmVwcGVkIERhdGEvRXhhbXBsZSBEYXRhIiwgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICIuUGl0Y2giLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IEYpICU+JQogICAgZHBseXI6OnJlbmFtZShQaXRjaCA9IFYxKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoUGl0Y2ggPSBnc3ViKCItLXVuZGVmaW5lZC0tIixOQSxQaXRjaCksCiAgICAgICAgICAgICAgICAgIFBpdGNoID0gYXMubnVtZXJpYyhQaXRjaCkpCgpGb3JtYW50c19QUkFBVCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwYXN0ZSgiUHJlcHBlZCBEYXRhL0V4YW1wbGUgRGF0YSIsIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiX0Zvcm1hbnQiLCBpZ25vcmUuY2FzZSA9IFQpICU+JQogICAgcGFzdGUoIlByZXBwZWQgRGF0YS9FeGFtcGxlIERhdGEvIiwuLCBzZXAgPSAiIikgJT4lCiAgICByZWFkLmRlbGltKC4sIGhlYWRlciA9IFQpICU+JQogICAgZHBseXI6OnNlbGVjdCghYyhuZm9ybWFudHMsIEIxLkh6LiwgQjIuSHouLCBCMy5Iei4sIEY0Lkh6LiwgQjQuSHouLCBGNS5Iei4sIEI1Lkh6LikpICU+JQogICAgZHBseXI6OnJlbmFtZShUaW1lX3MgPSB0aW1lLnMuLAogICAgICAgICAgICAgICAgICBGMV9IeiA9IEYxLkh6LiwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBGMi5Iei4sCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gRjMuSHouKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfSHogPSBpZmVsc2UoRjFfSHogPT0gMCwgTkEsIEYxX0h6KSwKICAgICAgICAgICAgICAgICAgRjJfSHogPSBpZmVsc2UoRjJfSHogPT0gMCwgTkEsIEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfSHogPSBpZmVsc2UoRjNfSHogPT0gMCwgTkEsIEYzX0h6KSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKEYxX0h6ID0gYXMubnVtZXJpYyhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX0h6ID0gYXMubnVtZXJpYyhGMl9IeiksCiAgICAgICAgICAgICAgICAgIEYzX0h6ID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKEYzX0h6KSksCiAgICAgICAgICAgICAgICAgIFRpbWVfbXMgPSBUaW1lX3MgLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9rSHogPSBGMV9IeiAvIDEwMDAsCiAgICAgICAgICAgICAgICAgIEYyX2tIeiA9IEYyX0h6IC8gMTAwMCwKICAgICAgICAgICAgICAgICAgRjNfa0h6ID0gRjNfSHogLyAxMDAwLAogICAgICAgICAgICAgICAgICBGMV9iID0gZW11Ujo6YmFyayhGMV9IeiksCiAgICAgICAgICAgICAgICAgIEYyX2IgPSBlbXVSOjpiYXJrKEYyX0h6KSwKICAgICAgICAgICAgICAgICAgRjNfYiA9IGVtdVI6OmJhcmsoRjNfSHopKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoIVRpbWVfcykgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVGltZV9tcywgLmJlZm9yZSA9IEYxX0h6KSAlPiUKICAgIGNiaW5kKC4sUGl0Y2hfUFJBQVQpICU+JQogICAgZHBseXI6OmZpbHRlcighaXMubmEoUGl0Y2gpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoRjFfbWFkID0gKGFicyhGMV9IeiAtIG1lZGlhbihGMV9IeikpLyBtYWQoRjFfSHosIGNvbnN0YW50ID0gMS40ODI2KSkgPiAyLjUsCiAgICAgICAgICAgICAgICAgIEYyX21hZCA9IChhYnMoRjJfSHogLSBtZWRpYW4oRjJfSHopKS8gbWFkKEYyX0h6LCBjb25zdGFudCA9IDEuNDgyNikpID4gMi41KSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIoRjFfbWFkID09IEZBTFNFICYgRjJfbWFkID09IEZBTFNFKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobURpc3QgPSBtYWhhbGFub2JpcyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xNZWFucyhjYmluZCguJEYxX0h6LCAuJEYyX0h6KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY292ID0gY292KGNiaW5kKC4kRjFfSHosIC4kRjJfSHopKSksCiAgICAgICAgICAgICAgICAgIG1EaXN0X3NkID0gYWJzKHNjYWxlKG1EaXN0LGNlbnRlciA9IFQpKSkgJT4lCiAgICAjZHBseXI6Om11dGF0ZShtRGlzdE91dGxpZXIgPSAoc3RhdHM6OnBjaGlzcShtRGlzdCwgZGY9MSwgbG93ZXIudGFpbD1GQUxTRSkpIDwgLjAwMSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKG1EaXN0X3NkIDwgMS41KQogIAogIGMgPC0gMgogIHdoaWxlKGMgPCBOUk9XKEZvcm1hbnRzX1BSQUFUKSl7CiAgICBGb3JtYW50c19QUkFBVCRGMV9IeltjXSA8LSBpZmVsc2UoaXMubmEoRm9ybWFudHNfUFJBQVQkRjFfSHpbYy0xXSkgJiYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYxX0h6W2MrMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvcm1hbnRzX1BSQUFUJEYxX0h6W2NdKQogICAgRm9ybWFudHNfUFJBQVQkRjJfSHpbY10gPC0gaWZlbHNlKGlzLm5hKEZvcm1hbnRzX1BSQUFUJEYyX0h6W2MtMV0pICYmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShGb3JtYW50c19QUkFBVCRGMl9IeltjKzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGb3JtYW50c19QUkFBVCRGMl9IeltjXSkKICAgIGMgPC0gYyArIDEKICB9CiAgcm0oYykKICAKICAgIEh1bGxfYiA8LSBjSHVsbChGb3JtYW50c19QUkFBVCRGMV9iLCBGb3JtYW50c19QUkFBVCRGMl9iKQojIyMgUGxvdHRpbmcgSHVsbAogICAgICBjb252ZXhDb29yZHMgPC0gRm9ybWFudHNfUFJBQVQgJT4lCiAgICAgICAgZHBseXI6OnNlbGVjdChGMV9iLCBGMl9iKSAlPiUKICAgICAgICBhcy5tYXRyaXgoKSAlPiUKICAgICAgICBnckRldmljZXM6OmNodWxsKCkKICAgICAgY29udmV4IDwtIEZvcm1hbnRzX1BSQUFUICU+JQogICAgICAgIHNsaWNlKGNvbnZleENvb3JkcykKCiAgICAgIGh1bGxQbG90XzEuNSA8LSBnZ3Bsb3QoYWVzKEYyX2IsIEYxX2IpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IEZvcm1hbnRzX1BSQUFUKSArCiAgICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxKSArCiAgICAgICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBjb252ZXgsCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjUsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMxMjc5QjUiLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpICsKICAgICAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSB0ZXh0X3gsIHkgPSB0ZXh0X3ksIGxhYmVsID0gcGFzdGUoIkh1bGwgPSIscm91bmQoSHVsbF9iLDIpKSkgKwogICAgICAgIHNjYWxlX3lfcmV2ZXJzZSgpICsKICAgICAgICBzY2FsZV94X3JldmVyc2UoKSArCiAgICAgICAgeGxpbSh4bGltcykgKwogICAgICAgIHlsaW0oeWxpbXMpICsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIjEuNSBTRCIpKSArIHhsYWIoIkYyIChCYXJrKSIpICsgeWxhYigiRjEgKEJhcmspIikgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDEpCiAgICAgIGh1bGxQbG90XzEuNQogICAgICAKIyBDb21iaW5lZCAtLS0tCiAgICAgIGdncHVicjo6Z2dhcnJhbmdlKGh1bGxQbG90XzEuNSwgaHVsbFBsb3RfMiwgaHVsbFBsb3RfMi41LCBodWxsUGxvdF8zLAogICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gNCkKICAgICAgZ2dzYXZlKGZpbGVuYW1lID0gIlBsb3RzL0h1bGwgYXQgRGlmZmVyZW50IEZpbHRlcnMucG5nIiwKICAgICAgICAgICAgIGhlaWdodCA9IDMsCiAgICAgICAgICAgICB3aWR0aD0gOSwKICAgICAgICAgICAgIHVuaXRzID0gImluIiwKICAgICAgICAgICAgIHNjYWxlID0gLjkpCiAgICAgIApgYGAKCiMgTGlzdGVuZXIgRGVtb2dyYXBoaWMgSW5mb3JtYXRpb24KYGBge3J9CgpMaXN0ZW5lckRlbW8gPC0gTGlzdGVuZXJzICU+JQogIGZ1cm5pdHVyZTo6dGFibGUxKGFnZSwgZ2VuZGVyLCByYWNlLCBldGhuaWNpdHkpCgpMaXN0ZW5lckRlbW8KCmBgYAoKIyBTcGVha2VyIERlbW9ncmFwaGljcwoKYGBge3J9CgpTcGVha2VyRGVtbyA8LSBBY291c3RpY0RhdGEgJT4lCiAgZHBseXI6OnNlbGVjdChjKFNwZWFrZXIsIFNleCwgRXRpb2xvZ3kpKQoKQWdlcyA8LSByaW86OmltcG9ydCgiUHJlcHBlZCBEYXRhL1NwZWFrZXIgQWdlcy54bHN4IikKClNwZWFrZXJEZW1vIDwtIGZ1bGxfam9pbihTcGVha2VyRGVtbywgQWdlcywgYnkgPSAiU3BlYWtlciIpCgpTcGVha2VyRGVtb0luZm8gPC0gU3BlYWtlckRlbW8gJT4lCiAgZnVybml0dXJlOjp0YWJsZTEoU2V4LCBFdGlvbG9neSwgQWdlLCBuYS5ybSA9IEYpCgpTcGVha2VyRGVtb0luZm8KClNwZWFrZXJEZW1vICU+JQogIGRwbHlyOjpzdW1tYXJpemUobWVhbl9hZ2UgPSBtZWFuKEFnZSwgbmEucm0gPSBUKSwgYWdlX3NkID0gc2QoQWdlLCBuYS5ybSA9IFQpLCBhZ2VfcmFuZ2UgPSByYW5nZShBZ2UsIG5hLnJtID0gVCkpCgpgYGAKCg==